<?php

namespace App\Services;

use App\Models\Siswa;
use App\Models\Tagihan;
use App\Models\TahunAjaran;
use App\Models\TarifPembayaran;
use Illuminate\Support\Facades\DB;

class TagihanService
{
    /**
     * MAIN ENTRY
     */
    /**
     * Entry point for generating tagihan for the active month.
     * This method is now idempotent – it will run only once per request.
     * Subsequent calls are ignored.
     */
    public static $alreadyGenerated = false;

    public function autoGenerateActiveMonth()
    {
        if (self::$alreadyGenerated) {
            return; // already executed, skip
        }
        self::$alreadyGenerated = true;
        $this->autoGenerateUpToCurrentMonth();
    }

    /**
     * FIX: SPP + DPP generator aman dari duplikat
     */
    public function autoGenerateUpToCurrentMonth()
    {
        $tahunAjaranAktif = TahunAjaran::aktif()->first();
        if (!$tahunAjaranAktif) return;

        $now = now();
        $bulanNow = (int) $now->format('n');
        $tahunNow = (int) $now->format('Y');

        $semuaBulan = $tahunAjaranAktif->getBulanSppList();
        $mulai = $tahunAjaranAktif->bulan_mulai_spp ?: 7;
        $tahunAwal = (int) substr($tahunAjaranAktif->tahun, 0, 4);

        $siswaList = Siswa::where('status', 'aktif')
            ->whereHas('siswaKelasHistory', function ($q) use ($tahunAjaranAktif) {
                $q->where('tahun_ajaran_id', $tahunAjaranAktif->id);
            })
            ->with(['siswaKelasHistory' => function ($q) use ($tahunAjaranAktif) {
                $q->where('tahun_ajaran_id', $tahunAjaranAktif->id);
            }, 'siswaKelasHistory.kelas'])
            ->get();

        foreach ($siswaList as $siswa) {
            $siswaKelasRecord = $siswa->siswaKelasHistory->first();
            $kelas = $siswaKelasRecord?->kelas;
            if (!$kelas) {
                continue;
            }

            foreach ($semuaBulan as $bulan) {
                $tahunTagihan = ($bulan < $mulai) ? $tahunAwal + 1 : $tahunAwal;

                $this->generateTagihanBulanSafe(
                    $siswa,
                    $kelas,
                    $tahunAjaranAktif,
                    $bulan,
                    $tahunTagihan
                );
            }
        }
    }

    /**
     * FIX TOTAL DPP (NO DOUBLE INSERT)
     */
    public function generateDppTagihan(Siswa $siswa, ?TahunAjaran $tahunAjaran = null)
    {
        $tahunAjaran = $tahunAjaran ?? TahunAjaran::aktif()->first();
        if (!$tahunAjaran) return;

        // Retrieve the student's class for this specific school year
        $siswaKelasRecord = $siswa->siswaKelasHistory()
            ->where('tahun_ajaran_id', $tahunAjaran->id)
            ->first();
        $kelas = $siswaKelasRecord?->kelas;

        if (!$kelas) {
            return;
        }

        DB::transaction(function () use ($siswa, $kelas, $tahunAjaran) {

            // Ambil tarif DPP berdasarkan jenis, tahun ajaran, kelas/jenjang, dan kategori siswa (jika ada)
            $tarifDPP = TarifPembayaran::where('jenis', 'DPP')
                ->where('status', 'aktif')
                ->where('tahun_ajaran_id', $tahunAjaran->id)
                ->where(function ($q) use ($kelas) {
                    $q->where('kelas_id', $kelas->id)
                       ->orWhere('jenjang', $kelas->jenjang);
                })
                ->when(!empty($siswa->kategori), function ($q) use ($siswa) {
                    $q->where('kategori_siswa', $siswa->kategori);
                })
                ->first();

            if (!$tarifDPP) {
                // No matching DPP tariff for this student's jenjang/class; skip DPP tagihan creation
                return;
            }

            // 1. Cek idempoten: sudah ada DPP di tahun ajaran INI?
            $existingDppTahunIni = Tagihan::where('siswa_id', $siswa->id)
                ->where('tahun_ajaran_id', $tahunAjaran->id)
                ->whereHas('tarifPembayaran', function ($q) {
                    $q->where('jenis', 'DPP');
                })
                ->exists();

            if ($existingDppTahunIni) {
                return; // Sudah ada untuk tahun ajaran ini, skip
            }

            // 2. Cek carry-over: siswa pernah punya DPP di jenjang YANG SAMA di tahun lain?
            $existingDppJenjangSama = Tagihan::where('siswa_id', $siswa->id)
                ->where('tahun_ajaran_id', '!=', $tahunAjaran->id)
                ->whereHas('tarifPembayaran', function ($q) use ($kelas) {
                    $q->where('jenis', 'DPP')
                      ->where('jenjang', $kelas->jenjang);
                })
                ->exists();

            if ($existingDppJenjangSama) {
                return; // carry-over: jenjang sama, tidak perlu DPP baru
            }

            Tagihan::create([
                'siswa_id'            => $siswa->id,
                'kelas_id'            => $kelas->id,
                'tahun_ajaran_id'     => $tahunAjaran->id,
                'tarif_pembayaran_id' => $tarifDPP->id,
                'bulan'               => null,
                'tahun'               => (int) substr($tahunAjaran->tahun, 0, 4),
                'jumlah_tagihan'      => $tarifDPP->nominal,
                'jumlah_terbayar'     => 0,
                'status'              => 'belum_bayar',
            ]);
        });
    }

    /**
     * Generate all SPP and DPP tagihan for a specific student for a given year.
     */
    public function generateTagihanSiswa($siswa, $kelas, $tahunAjaran)
    {
        if ($tahunAjaran->status !== 'aktif') return;

        // Generate DPP
        $this->generateDppTagihan($siswa, $tahunAjaran);

        // Generate SPP
        $semuaBulan = $tahunAjaran->getBulanSppList();
        $mulai = $tahunAjaran->bulan_mulai_spp ?: 7;
        $tahunAwal = (int) substr($tahunAjaran->tahun, 0, 4);

        foreach ($semuaBulan as $bulan) {
            $tahunTagihan = ($bulan < $mulai) ? $tahunAwal + 1 : $tahunAwal;
            $this->generateTagihanBulanSafe(
                $siswa,
                $kelas,
                $tahunAjaran,
                $bulan,
                $tahunTagihan
            );
        }
    }

    /**
     * FIX TOTAL SPP (ANTI DOBLE LEVEL DB)
     */
    public function generateTagihanBulanSafe($siswa, $kelas, $tahunAjaran, $bulan, $tahunTujuan)
    {
        // Ambil tarif SPP berdasarkan tahun ajaran, kelas/jenjang, dan status aktif
        $tarifSPP = TarifPembayaran::where('jenis', 'SPP')
            ->where('status', 'aktif')
            ->where('tahun_ajaran_id', $tahunAjaran->id)
            ->where(function ($q) use ($kelas) {
                $q->where('kelas_id', $kelas->id)
                  ->orWhere('jenjang', $kelas->jenjang);
            })
            ->first();

        // Fallback: cari tarif SPP aktif untuk tahun ajaran tanpa filter kelas/jenjang
       if (!$tarifSPP) {
            \Log::warning(
                'Tarif SPP tidak ditemukan untuk jenjang ' . $kelas->jenjang
            );
            return;
        }

        DB::transaction(function () use ($siswa, $kelas, $tahunAjaran, $bulan, $tahunTujuan, $tarifSPP) {
            // Use updateOrCreate to guarantee idempotency under race conditions.
            Tagihan::firstOrCreate(
            [
                'siswa_id'            => $siswa->id,
                'kelas_id'            => $kelas->id,
                'tahun_ajaran_id'     => $tahunAjaran->id,
                'bulan'               => $bulan,
            ],
            [
                'tarif_pembayaran_id' => $tarifSPP->id,
                'tahun'               => $tahunTujuan,
                'jumlah_tagihan'      => $tarifSPP->nominal,
                'jumlah_terbayar'     => 0,
                'status'              => 'belum_bayar',
            ]
        );
        });
    }
}