<?php

namespace App\Http\Controllers\Siswa;

use App\Http\Controllers\Controller;
use App\Models\Leaderboard;
use App\Models\Siswa;
use App\Models\SiswaBadge;
use App\Services\BadgeService;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Storage;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;

class LeaderboardController extends Controller
{
    /**
     * Hitung total EXP siswa secara dinamis langsung dari database.
     *
     * Formula:
     *   + 1  poin per soal benar di setiap challenge
     *   +10  poin per tugas yang dikumpulkan tepat waktu
     *   + 5  poin per tugas yang terlambat < 1 hari  (grace period)
     *   + 3  poin per tugas yang terlambat 2–3 hari
     *   - 5  poin per tugas yang terlambat > 3 hari
     *   - 5  poin per tugas yang tidak dikumpulkan sama sekali (setelah deadline)
     */
    private function hitungExpSiswa(int $idSiswa, int $idKelas): int
    {
        $now = Carbon::now();

        // ── 1. EXP dari challenge (soal yang dijawab benar) ──────────────
        $expChallenge = 0;

        $pesertaList = DB::table('peserta_challenges')
            ->where('id_siswa', $idSiswa)
            ->get();

        foreach ($pesertaList as $peserta) {
            $jawaban  = json_decode($peserta->jawaban, true) ?? [];
            $soalList = DB::table('soal_challenge')
                ->where('id_challenge', $peserta->id_challenge)
                ->get();

            foreach ($soalList as $soal) {
                $jwb = $jawaban[$soal->id_soal] ?? null;
                if ($jwb && strtoupper($jwb) === strtoupper($soal->jawaban_benar)) {
                    $expChallenge += 1; // +1 per soal benar
                }
            }
        }

        // ── 2. EXP dari tugas ────────────────────────────────────────────
        $semuaTugasIdKelas = DB::table('tugas')
            ->join('mengajars', 'tugas.id_mengajar', '=', 'mengajars.id_mengajar')
            ->where('mengajars.id_kelas', $idKelas)
            ->select('tugas.id_tugas', 'tugas.deadline')
            ->get();

        $expTugas = 0;

        foreach ($semuaTugasIdKelas as $tugas) {
            $deadline    = Carbon::parse($tugas->deadline);
            $pengumpulan = DB::table('pengumpulan_tugas')
                ->where('id_tugas', $tugas->id_tugas)
                ->where('id_siswa', $idSiswa)
                ->first();

            if ($pengumpulan && $pengumpulan->lampiran_tugas !== null) {
                $tanggalSubmit = Carbon::parse($pengumpulan->tanggal_submit);

                if ($tanggalSubmit->lessThanOrEqualTo($deadline)) {
                    $expTugas += 10; // Tepat waktu → +10
                } else {
                    $hariTerlambat = $deadline->diffInDays($tanggalSubmit); // ← dibalik

                    if ($hariTerlambat <= 1) {
                        $expTugas += 5;  // Terlambat ≤ 1 hari → +5
                    } elseif ($hariTerlambat <= 3) {
                        $expTugas += 1;  // Terlambat 2-3 hari → +3
                    } else {
                        $expTugas -= 5;  // Lewat grace period > 3 hari → dianggap tidak kumpul
                    }
                }
            } else {
                // Belum mengumpulkan file sama sekali
                if ($now->greaterThan($deadline)) {
                    // Deadline sudah lewat → penalti -5
                    $expTugas -= 5;
                }
                // Deadline belum lewat → tidak ada penalti, tidak ada poin
            }
        }

        // Total EXP tidak bisa negatif
        return max(0, $expChallenge + $expTugas);
    }

    /**
     * Ambil data leaderboard dengan EXP yang dihitung dinamis.
     */
    private function getData(): array
    {
        $siswa = Auth::guard('siswa')->user();

        $now         = Carbon::now();
        $semester    = $now->month >= 7 ? '1' : '2';
        $tahunAjaran = $now->month >= 7
            ? $now->year . '/' . ($now->year + 1)
            : ($now->year - 1) . '/' . $now->year;

        // Ambil semua siswa di kelas yang sama
        $semuaSiswa = Siswa::where('id_kelas', $siswa->id_kelas)->get();

        // Hitung EXP tiap siswa secara dinamis
        $leaderboard = $semuaSiswa->map(function ($s) {
            return [
                'id_siswa'    => $s->id_siswa,
                'nama'        => $s->nama,
                'nisn'        => $s->nisn,
                'foto_profil' => $s->foto_profil,
                'foto_url'    => $s->foto_profil ? Storage::url($s->foto_profil) : null,
                'exp'         => $this->hitungExpSiswa($s->id_siswa, $s->id_kelas),
            ];
        })
        ->sortByDesc('exp')
        ->values()
        ->map(function ($item, $i) {
            $item['ranking'] = $i + 1;
            return $item;
        });

        // Sinkronisasi ke tabel leaderboards agar badge bisa dicek
        foreach ($leaderboard as $item) {
            Leaderboard::updateOrCreate(
                [
                    'id_siswa'     => $item['id_siswa'],
                    'id_kelas'     => $siswa->id_kelas,
                    'semester'     => $semester,
                    'tahun_ajaran' => $tahunAjaran,
                ],
                [
                    'total_exp' => $item['exp'],
                    'ranking'   => $item['ranking'],
                ]
            );
        }

        $myRank = $leaderboard->firstWhere('id_siswa', $siswa->id_siswa);

        return compact('leaderboard', 'myRank', 'semester', 'tahunAjaran', 'siswa');
    }

    public function index()
    {
        $data = $this->getData();
        unset($data['siswa']);
        return view('siswa.leaderboard.index', $data);
    }

    /**
     * Endpoint JSON untuk polling real-time.
     */
    public function json()
    {
        $data  = $this->getData();
        $siswa = $data['siswa'];

        // Evaluasi badge leaderboard berdasarkan data terbaru
        app(BadgeService::class)->checkLeaderboardBadges(
            $siswa->id_siswa,
            $siswa->id_kelas
        );

        $badgeSiswa = SiswaBadge::with('badge')
            ->where('id_siswa', $siswa->id_siswa)
            ->whereHas('badge', fn($q) => $q->whereIn('syarat', ['leaderboard_top5', 'leaderboard_top1']))
            ->get()
            ->map(fn($sb) => [
                'id_badge'   => $sb->id_badge,
                'nama_badge' => $sb->badge->nama_badge,
                'deskripsi'  => $sb->badge->deskripsi,
                'icon_url'   => asset($sb->badge->icon_badge),
            ]);

        unset($data['siswa']);
        $data['badgeSiswa'] = $badgeSiswa;

        return response()->json($data);
    }
}