<?php

namespace App\Http\Controllers\Admin;

use App\Http\Controllers\Controller;
use App\Models\Absensi;
use App\Models\Guru;
use App\Models\HariLibur;
use App\Models\Siswa;
use Carbon\Carbon;
use Illuminate\Http\Request;

class AbsensiController extends Controller
{
    // ---------------------------------------------------------------
    // Halaman scan QR
    // ---------------------------------------------------------------

    public function scan()
    {
        return view('absensi.scan');
    }

    // ---------------------------------------------------------------
    // Proses absen — entry point (guru & siswa)
    // ---------------------------------------------------------------

    public function prosesAbsen(Request $request)
    {
        try {
            $request->validate(['qr_code' => 'required']);

            Carbon::setLocale('id');
            $now      = Carbon::now('Asia/Jakarta');
            $hari     = $now->isoFormat('dddd');
            $jam_scan = $now->format('H:i');
            $tanggal  = $now->toDateString();

            // Cek hari libur
            $libur = HariLibur::where(function ($q) use ($tanggal) {
                $q->whereNotNull('tanggal_selesai')
                    ->whereDate('tanggal_mulai', '<=', $tanggal)
                    ->whereDate('tanggal_selesai', '>=', $tanggal);
            })->orWhere(function ($q) use ($tanggal) {
                $q->whereNull('tanggal_selesai')
                    ->whereDate('tanggal_mulai', $tanggal);
            })->first();

            if ($libur) {
                return response()->json([
                    'status'  => 'error',
                    'message' => 'Hari ini libur: ' . $libur->keterangan,
                ]);
            }

            // Deteksi jenis QR
            if (str_starts_with($request->qr_code, 'GURU-')) {
                return $this->prosesAbsenGuru($request->qr_code, $jam_scan, $tanggal);
            }

            return $this->prosesAbsenSiswa($request->qr_code, $hari, $jam_scan, $tanggal);
        } catch (\Exception $e) {
            return response()->json([
                'status'  => 'error',
                'message' => 'Terjadi kesalahan sistem.',
            ], 500);
        }
    }

    // ---------------------------------------------------------------
    // Proses absen guru
    // ---------------------------------------------------------------

    private function prosesAbsenGuru(string $qr_code, string $jam_scan, string $tanggal)
    {
        $nomor_identitas = str_replace('GURU-', '', $qr_code);

        $guru = Guru::where('nomor_identitas', $nomor_identitas)->first();

        if (! $guru) {
            return response()->json([
                'status'  => 'error',
                'message' => 'Data guru tidak ditemukan!',
            ]);
        }

        // Tentukan kategori berdasarkan jam
        $kategori = match (true) {
            $jam_scan >= '07:00' && $jam_scan <= '08:30' => 'Masuk',
            $jam_scan >= '13:00' && $jam_scan <= '15:00' => 'Pulang',
            default                                       => null,
        };

        if (! $kategori) {
            return response()->json([
                'status'  => 'error',
                'message' => 'Absen guru: 07:00–08:00 (Masuk) & 13:00–15:00 (Pulang).',
            ]);
        }

        // Cek duplikasi absen
        $sudahAbsen = Absensi::where('guru_id', $guru->id)
            ->where('kategori', $kategori)
            ->whereDate('tanggal', $tanggal)
            ->exists();

        if ($sudahAbsen) {
            return response()->json([
                'status'  => 'warning',
                'message' => "Halo {$guru->nama}, Anda sudah absen {$kategori} hari ini.",
                'nama'    => $guru->nama,
                'kelas'   => 'GURU',
            ]);
        }

        Absensi::create([
            'guru_id'  => $guru->id,
            'kategori' => $kategori,
            'tanggal'  => $tanggal,
            'jam_scan' => $jam_scan,
            'status'   => 'Hadir',
        ]);

        return response()->json([
            'status'  => 'success',
            'message' => "Halo {$guru->nama}, berhasil absen {$kategori}.",
            'nama'    => $guru->nama,
            'kelas'   => 'GURU',
        ]);
    }

    // ---------------------------------------------------------------
    // Proses absen siswa
    // ---------------------------------------------------------------

    private function prosesAbsenSiswa(string $qr_code, string $hari, string $jam_scan, string $tanggal)
    {
        $siswa = Siswa::where('nisn', $qr_code)
            ->orWhere('qr_code', $qr_code)
            ->first();

        if (! $siswa) {
            return response()->json([
                'status'  => 'error',
                'message' => 'QR Code tidak terdaftar!',
            ]);
        }

        // Tentukan jenis kegiatan berdasarkan jam & hari
        $ibadah = null;

        if ($jam_scan >= '07:00' && $jam_scan <= '08:30') {
            $ibadah = match ($hari) {
                'Senin'  => 'Upacara',
                'Jumat'  => 'Tadarus',
                default  => 'Duha',
            };
        } elseif ($jam_scan >= '12:30' && $jam_scan <= '15:00' && $hari !== 'Jumat') {
            $ibadah = 'Dzuhur';
        } elseif ($hari === 'Jumat' && $jam_scan >= '11:00' && $jam_scan <= '15:00') {
            $ibadah = 'Pulang';
        }

        if (! $ibadah) {
            return response()->json([
                'status'  => 'error',
                'message' => "Belum waktunya absen siswa (sekarang {$jam_scan}).",
            ]);
        }

        // Cek duplikasi absen
        $sudahAbsen = Absensi::where('siswa_id', $siswa->id)
            ->where('kategori', $ibadah)
            ->whereDate('tanggal', $tanggal)
            ->exists();

        if ($sudahAbsen) {
            return response()->json([
                'status'  => 'warning',
                'message' => "{$siswa->nama} sudah absen {$ibadah}.",
                'nama'    => $siswa->nama,
                'kelas'   => $siswa->kelas,
            ]);
        }

        Absensi::create([
            'siswa_id' => $siswa->id,
            'kategori' => $ibadah,
            'tanggal'  => $tanggal,
            'jam_scan' => $jam_scan,
            'status'   => 'Hadir',
        ]);

        return response()->json([
            'status'  => 'success',
            'message' => "Berhasil absen {$ibadah}.",
            'nama'    => $siswa->nama,
            'kelas'   => $siswa->kelas,
        ]);
    }

    public function daftarBelumHadir(Request $request)
    {
        $request->validate([
            'tipe'  => 'required|in:siswa,guru',
            'kelas' => 'nullable|string',
        ]);

        Carbon::setLocale('id');
        $now     = Carbon::now('Asia/Jakarta');
        $tanggal = $now->toDateString();
        $hari    = $now->isoFormat('dddd');
        $jamScan = $now->format('H:i');

        if ($request->tipe === 'siswa') {
            $kategoriAktif = $this->getKategoriAktifSiswa($hari, $jamScan);

            $query = Siswa::query();

            if ($kategoriAktif) {
                $sudahTercatatIds = Absensi::whereDate('tanggal', $tanggal)
                    ->whereNotNull('siswa_id')
                    ->where('kategori', $kategoriAktif)
                    ->pluck('siswa_id');

                $query->whereNotIn('id', $sudahTercatatIds);
            }

            if ($request->filled('kelas')) {
                $query->where('kelas', $request->kelas);
            }

            $daftar = $query->orderBy('nama')->get(['id', 'nama', 'nisn', 'kelas', 'jenis_kelamin']);

            return response()->json($daftar->map(fn($s) => [
                'id'            => $s->id,
                'nama'          => $s->nama,
                'kode'          => $s->nisn,
                'kelas'         => $s->kelas,
                'jenis_kelamin' => $s->jenis_kelamin,
            ]));
        }

        $kategoriAktifGuru = $this->getKategoriAktifGuru($jamScan);

        $queryGuru = Guru::query();

        if ($kategoriAktifGuru) {
            $sudahTercatatIds = Absensi::whereDate('tanggal', $tanggal)
                ->whereNotNull('guru_id')
                ->where('kategori', $kategoriAktifGuru)
                ->pluck('guru_id');

            $queryGuru->whereNotIn('id', $sudahTercatatIds);
        }

        $daftar = $queryGuru->orderBy('nama')->get(['id', 'nama', 'nomor_identitas']);

        return response()->json($daftar->map(fn($g) => [
            'id'   => $g->id,
            'nama' => $g->nama,
            'kode' => 'GURU-' . $g->nomor_identitas,
        ]));
    }

    // ---------------------------------------------------------------
    // Input manual — Hadir / Sakit / Izin / Haid 
    // ---------------------------------------------------------------

    public function inputManual(Request $request)
    {
        $request->validate([
            'kode'     => 'required|string',
            'jenis'    => 'required|in:Hadir,Sakit,Izin,Haid',
            'kategori' => 'nullable|string',
        ], [
            'kode.required'  => 'Masukkan NISN atau kode guru terlebih dahulu.',
            'jenis.required' => 'Pilih jenis keterangan.',
            'jenis.in'       => 'Jenis keterangan tidak valid.',
        ]);

        try {
            Carbon::setLocale('id');
            $now      = Carbon::now('Asia/Jakarta');
            $hari     = $now->isoFormat('dddd');
            $tanggal  = $now->toDateString();
            $jam_scan = $now->format('H:i');

            // ── GURU ──────────────────────────────────────────────
            if (str_starts_with($request->kode, 'GURU-')) {
                if ($request->jenis === 'Haid') {
                    return response()->json(['status' => 'error', 'message' => 'Status Haid tidak berlaku untuk guru.']);
                }

                $nomor_identitas = str_replace('GURU-', '', $request->kode);
                $guru = Guru::where('nomor_identitas', $nomor_identitas)->first();

                if (! $guru) {
                    return response()->json(['status' => 'error', 'message' => 'Data guru tidak ditemukan!']);
                }

                // Jika Hadir, hanya catat 1 kategori yang dipilih[cite: 12]
                if ($request->jenis === 'Hadir') {
                    if (! $request->filled('kategori')) {
                        return response()->json(['status' => 'error', 'message' => 'Pilih kegiatan terlebih dahulu.']);
                    }

                    Absensi::updateOrCreate(
                        ['guru_id' => $guru->id, 'kategori' => $request->kategori, 'tanggal' => $tanggal],
                        ['jam_scan' => $jam_scan, 'status' => 'Hadir']
                    );

                    return response()->json([
                        'status'  => 'success',
                        'message' => "{$guru->nama} berhasil diabsen Hadir untuk {$request->kategori}.",
                        'nama'    => $guru->nama,
                        'kelas'   => 'GURU',
                    ]);
                }

                // Sakit/Izin guru berlaku untuk seluruh kegiatan hari itu (Masuk & Pulang)[cite: 12]
                foreach (['Masuk', 'Pulang'] as $kat) {
                    Absensi::updateOrCreate(
                        ['guru_id' => $guru->id, 'kategori' => $kat, 'tanggal' => $tanggal],
                        ['jam_scan' => $jam_scan, 'status' => $request->jenis]
                    );
                }

                return response()->json([
                    'status'  => 'success',
                    'message' => "{$guru->nama} ditandai {$request->jenis} untuk hari ini.",
                    'nama'    => $guru->nama,
                    'kelas'   => 'GURU',
                ]);
            }

            // ── SISWA ─────────────────────────────────────────────
            $siswa = Siswa::where('nisn', $request->kode)->orWhere('qr_code', $request->kode)->first();

            if (! $siswa) {
                return response()->json(['status' => 'error', 'message' => 'QR Code / NISN tidak terdaftar!']);
            }

            $jadwalHariIni = $this->getJadwalSiswaByHari($hari);

            if (empty($jadwalHariIni)) {
                return response()->json(['status' => 'error', 'message' => 'Tidak ada jadwal kegiatan siswa hari ini.']);
            }

            // Hadir & Haid butuh kategori[cite: 12]
            if ($request->jenis === 'Haid' || $request->jenis === 'Hadir') {
                if ($request->jenis === 'Haid' && $siswa->jenis_kelamin !== 'P') {
                    return response()->json(['status' => 'error', 'message' => 'Status Haid hanya berlaku untuk siswi.']);
                }
                if (! $request->filled('kategori')) {
                    return response()->json(['status' => 'error', 'message' => 'Pilih kegiatan terlebih dahulu.']);
                }
                if (! in_array($request->kategori, $jadwalHariIni)) {
                    return response()->json(['status' => 'error', 'message' => 'Kegiatan tersebut tidak ada di jadwal hari ini.']);
                }

                Absensi::updateOrCreate(
                    ['siswa_id' => $siswa->id, 'kategori' => $request->kategori, 'tanggal' => $tanggal],
                    ['jam_scan' => $jam_scan, 'status' => $request->jenis]
                );

                return response()->json([
                    'status'  => 'success',
                    'message' => "{$siswa->nama} ditandai {$request->jenis} untuk {$request->kategori}.",
                    'nama'    => $siswa->nama,
                    'kelas'   => $siswa->kelas,
                ]);
            }

            // Sakit / Izin: berlaku untuk SEMUA kegiatan terjadwal hari ini[cite: 12]
            foreach ($jadwalHariIni as $kat) {
                Absensi::updateOrCreate(
                    ['siswa_id' => $siswa->id, 'kategori' => $kat, 'tanggal' => $tanggal],
                    ['jam_scan' => $jam_scan, 'status' => $request->jenis]
                );
            }

            return response()->json([
                'status'  => 'success',
                'message' => "{$siswa->nama} ditandai {$request->jenis} untuk semua kegiatan hari ini.",
                'nama'    => $siswa->nama,
                'kelas'   => $siswa->kelas,
            ]);
        } catch (\Exception $e) {
            return response()->json(['status' => 'error', 'message' => 'Gagal menyimpan: ' . $e->getMessage()], 500);
        }
    }

    private function getJadwalSiswaByHari(string $hariIndo): array
    {
        return match ($hariIndo) {
            'Senin'                                     => ['Upacara', 'Dzuhur'],
            'Selasa', 'Rabu', 'Kamis', 'Sabtu'          => ['Duha', 'Dzuhur'],
            'Jumat'                                      => ['Tadarus', 'Pulang'],
            default                                      => [],
        };
    }

    private function getKategoriAktifSiswa(string $hariIndo, string $jamScan): ?string
    {
        if ($jamScan >= '07:00' && $jamScan <= '08:30') {
            return match ($hariIndo) {
                'Senin' => 'Upacara',
                'Jumat' => 'Tadarus',
                default => 'Duha',
            };
        }

        if ($jamScan >= '12:20' && $jamScan <= '15:00' && $hariIndo !== 'Jumat') {
            return 'Dzuhur';
        }

        if ($hariIndo === 'Jumat' && $jamScan >= '11:00' && $jamScan <= '15:00') {
            return 'Pulang';
        }

        return null;
    }

    private function getKategoriAktifGuru(string $jamScan): ?string
    {
        return match (true) {
            $jamScan >= '07:00' && $jamScan <= '08:30' => 'Masuk',
            $jamScan >= '12:30' && $jamScan <= '15:00' => 'Pulang',
            default                                     => null,
        };
    }

    // ---------------------------------------------------------------
    // Rekap harian
    // ---------------------------------------------------------------

    public function rekapHarian(Request $request)
    {
        $tanggal = $request->get('tanggal', date('Y-m-d'));

        Carbon::setLocale('id');
        $now      = Carbon::parse($tanggal);
        $namaHari = $now->isoFormat('dddd');

        $daftar_kelas = [
            'VII-A',
            'VII-B',
            'VII-C',
            'VII-D',
            'VIII-A',
            'VIII-B',
            'VIII-C',
            'VIII-D',
            'IX-A',
            'IX-B',
            'IX-C',
            'IX-D',
        ];

        // Jadwal ibadah sesuai hari
        $jadwal = match (true) {
            $namaHari === 'Senin'                                         => ['Upacara', 'Dzuhur'],
            in_array($namaHari, ['Selasa', 'Rabu', 'Kamis', 'Sabtu'])    => ['Duha', 'Dzuhur'],
            $namaHari === 'Jumat'                                         => ['Tadarus'],
            default                                                       => [],
        };

        // Rekap siswa
        $querySiswa = Siswa::query();

        if ($request->filled('kelas')) {
            $querySiswa->where('kelas', $request->kelas);
        }

        $rekap = $querySiswa->orderBy('nama')->get()->map(function ($s) use ($jadwal, $tanggal) {
            $ibadahData = [];

            foreach ($jadwal as $ib) {
                $absen = Absensi::where('siswa_id', $s->id)
                    ->where('kategori', $ib)
                    ->whereDate('tanggal', $tanggal)
                    ->first();

                $ibadahData[$ib] = [
                    'status'   => $absen ? $absen->status : 'Tidak',
                    'jam_scan' => $absen->jam_scan ?? '--:--',
                ];
            }

            return [
                'nisn'   => $s->nisn,
                'nama'   => $s->nama,
                'kelas'  => $s->kelas,
                'ibadah' => $ibadahData,
            ];
        })->toArray();

        // Rekap guru
        $rekapGuru = Guru::orderBy('nama')->get()->map(function ($g) use ($tanggal) {
            $masuk  = Absensi::where('guru_id', $g->id)->where('kategori', 'Masuk')->whereDate('tanggal', $tanggal)->first();
            $pulang = Absensi::where('guru_id', $g->id)->where('kategori', 'Pulang')->whereDate('tanggal', $tanggal)->first();

            return [
                'nama'             => $g->nama,
                'nomor_identitas'  => $g->nomor_identitas,
                'kegiatan'         => [
                    'Masuk'  => ['status' => $masuk  ? 'Hadir' : 'Tidak', 'jam_scan' => $masuk->jam_scan  ?? '--:--'],
                    'Pulang' => ['status' => $pulang ? 'Hadir' : 'Tidak', 'jam_scan' => $pulang->jam_scan ?? '--:--'],
                ],
            ];
        })->toArray();

        return view('absensi.rekap_harian', compact(
            'tanggal',
            'namaHari',
            'jadwal',
            'rekap',
            'rekapGuru',
            'daftar_kelas',
        ));
    }
}
