<?php

namespace App\Services;

use App\Models\Badge;
use App\Models\SiswaBadge;
use App\Models\PesertaChallenge;
use App\Models\PengumpulanTugas;
use App\Models\Leaderboard;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;

class BadgeService
{
    /**
     * Syarat (kolom `syarat` di tabel badges) yang dikenali sistem.
     * Nilai ini harus sama persis dengan isi kolom `syarat` di DB.
     *
     * CHALLENGE
     *   challenge_1   → selesaikan 1 challenge
     *   challenge_3   → selesaikan 3 challenge
     *
     * TUGAS
     *   tugas_1       → kumpulkan 1 tugas (tepat waktu)
     *   tugas_3       → kumpulkan 3 tugas (tepat waktu)
     *
     * LEADERBOARD  (dicek & dicabut secara real-time)
     *   leaderboard_top5  → masuk top 5 leaderboard kelas aktif
     *   leaderboard_top1  → raih peringkat 1 leaderboard kelas aktif
     */

    // -------------------------------------------------------------------------
    // ENTRY POINTS
    // -------------------------------------------------------------------------

    /**
     * Dipanggil setelah siswa submit challenge.
     * Mengecek & memberikan badge challenge.
     */
    public function checkChallengeBadges(int $idSiswa): void
    {
        $jumlahSelesai = PesertaChallenge::where('id_siswa', $idSiswa)
            ->where('status', 'selesai')
            ->count();

        $this->grantIfEligible($idSiswa, 'challenge_1', $jumlahSelesai >= 1);
        $this->grantIfEligible($idSiswa, 'challenge_3', $jumlahSelesai >= 3);
    }

    /**
     * Dipanggil setelah siswa submit tugas.
     * Mengecek & memberikan badge tugas (hanya status 'dikumpulkan' / tepat waktu).
     */
    public function checkTugasBadges(int $idSiswa): void
    {
        $jumlahKumpul = PengumpulanTugas::where('id_siswa', $idSiswa)
            ->where('status', 'dikumpulkan')
            ->count();

        $this->grantIfEligible($idSiswa, 'tugas_1', $jumlahKumpul >= 1);
        $this->grantIfEligible($idSiswa, 'tugas_3', $jumlahKumpul >= 3);
    }

    /**
     * Dipanggil dari endpoint JSON leaderboard (polling real-time).
     * Badge leaderboard DICABUT jika siswa tidak lagi memenuhi syarat,
     * dan DIBERIKAN KEMBALI jika kembali memenuhi syarat.
     *
     * Hanya leaderboard semester & tahun ajaran aktif yang dievaluasi.
     */
    public function checkLeaderboardBadges(int $idSiswa, int $idKelas): void
    {
        [$semester, $tahunAjaran] = $this->semesterAktif();

        $lb = Leaderboard::where('id_siswa', $idSiswa)
            ->where('id_kelas', $idKelas)
            ->where('semester', $semester)
            ->where('tahun_ajaran', $tahunAjaran)
            ->first();

        $ranking = $lb?->ranking ?? 0;

        // top5: ranking 1-5, top1: hanya ranking 1
        $isTop5 = $ranking >= 1 && $ranking <= 5;
        $isTop1 = $ranking === 1;

        // Untuk badge leaderboard: grant jika eligible, revoke jika tidak
        $this->grantOrRevoke($idSiswa, 'leaderboard_top5', $isTop5);
        $this->grantOrRevoke($idSiswa, 'leaderboard_top1', $isTop1);
    }

    // -------------------------------------------------------------------------
    // PRIVATE HELPERS
    // -------------------------------------------------------------------------

    /**
     * Berikan badge jika eligible. Tidak melakukan apa-apa jika sudah punya.
     * Digunakan untuk badge challenge & tugas (tidak pernah dicabut).
     */
    private function grantIfEligible(int $idSiswa, string $syarat, bool $eligible): void
    {
        if (!$eligible) {
            return;
        }

        $badge = Badge::where('syarat', $syarat)->first();
        if (!$badge) {
            return; // badge belum di-seed di DB, skip
        }

        // Idempoten: cek dulu sebelum insert
        $sudahPunya = SiswaBadge::where('id_siswa', $idSiswa)
            ->where('id_badge', $badge->id_badge)
            ->exists();

        if (!$sudahPunya) {
            SiswaBadge::create([
                'id_siswa'          => $idSiswa,
                'id_badge'          => $badge->id_badge,
                'tanggal_diberikan' => Carbon::now(),
            ]);
        }
    }

    /**
     * Berikan badge jika eligible, CABUT jika tidak.
     * Digunakan khusus untuk badge leaderboard (real-time).
     */
    private function grantOrRevoke(int $idSiswa, string $syarat, bool $eligible): void
    {
        $badge = Badge::where('syarat', $syarat)->first();
        if (!$badge) {
            return;
        }

        $record = SiswaBadge::where('id_siswa', $idSiswa)
            ->where('id_badge', $badge->id_badge)
            ->first();

        if ($eligible && !$record) {
            // Berikan badge
            SiswaBadge::create([
                'id_siswa'          => $idSiswa,
                'id_badge'          => $badge->id_badge,
                'tanggal_diberikan' => Carbon::now(),
            ]);
        } elseif (!$eligible && $record) {
            // Cabut badge
            $record->delete();
        }
        // Jika sudah punya & masih eligible, atau tidak punya & tidak eligible → tidak perlu apa-apa
    }

    /**
     * Mengembalikan [semester, tahun_ajaran] berdasarkan tanggal sekarang,
     * konsisten dengan logika di ChallengeController.
     */
    private function semesterAktif(): array
    {
        $now         = Carbon::now();
        $semester    = $now->month >= 7 ? '1' : '2';
        $tahunAjaran = $now->month >= 7
            ? $now->year . '/' . ($now->year + 1)
            : ($now->year - 1) . '/' . $now->year;

        return [$semester, $tahunAjaran];
    }
}