<?php

namespace App\Controllers\Admin;

use App\Controllers\BaseController;
use App\Models\QrScanLogModel;
use App\Models\StudentModel;

class AttendanceQr extends BaseController
{
    protected QrScanLogModel $scanModel;
    protected StudentModel   $studentModel;

    // Jam operasional scan (bisa dipindah ke tabel settings nanti)
    private string $scanStart = '00:00';
    private string $scanEnd   = '24:00';

    public function __construct()
    {
        $this->scanModel   = new QrScanLogModel();
        $this->studentModel = new StudentModel();
    }

    // ── Halaman scan utama ───────────────────────────────────────
    public function scanPage()
    {
        // Ambil setting jam dari tabel settings jika ada
        $db    = \Config\Database::connect();
        $start = $db->table('settings')->where('setting_key', 'qr_scan_start_time')->get()->getRowArray();
        $end   = $db->table('settings')->where('setting_key', 'qr_scan_end_time')->get()->getRowArray();
        if ($start) $this->scanStart = $start['setting_value'];
        if ($end)   $this->scanEnd   = $end['setting_value'];

        $today     = date('Y-m-d');
        $countToday = $this->scanModel->countToday($today);

        // Ambil daftar siswa aktif untuk pencarian nama/NISN
        $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        $students = [];
        if ($activePeriod) {
            $students = $db->table('student_academic_histories sah')
                ->select('s.nisn, s.full_name, c.name as classroom_name, g.name as grade_name')
                ->join('students s', 's.id = sah.student_id')
                ->join('classrooms c', 'c.id = sah.classroom_id', 'left')
                ->join('grades g', 'g.id = c.grade_id', 'left')
                ->where('sah.academic_period_id', $activePeriod['id'])
                ->where('s.deleted_at', null)
                ->where('s.status', 'Aktif')
                ->orderBy('s.full_name', 'ASC')
                ->get()->getResultArray();
        }

        return view('attendance/qr_scan', [
            'title'      => 'Absensi QR Code',
            'scan_start' => $this->scanStart,
            'scan_end'   => $this->scanEnd,
            'count_today' => $countToday,
            'today'      => $today,
            'students'   => $students,
        ]);
    }

    // ── AJAX: Proses scan QR ─────────────────────────────────────
    public function processScan()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setStatusCode(403)->setJSON(['success' => false]);
        }

        $nisn = trim($this->request->getJSON(true)['nisn'] ?? '');
        if (empty($nisn)) {
            return $this->response->setJSON(['success' => false, 'message' => 'NISN kosong.']);
        }

        // Ambil setting dari DB (fresh setiap request)
        $db = \Config\Database::connect();
        $settingRows = $db->table('settings')
            ->whereIn('setting_key', ['qr_scan_start_time', 'qr_scan_end_time', 'qr_scan_active'])
            ->get()->getResultArray();
        $cfg = [];
        foreach ($settingRows as $r) $cfg[$r['setting_key']] = $r['setting_value'];
        $scanStart  = $cfg['qr_scan_start_time'] ?? $this->scanStart;
        $scanEnd    = $cfg['qr_scan_end_time']   ?? $this->scanEnd;
        $scanActive = $cfg['qr_scan_active']      ?? '1';

        // Cek fitur aktif
        if ($scanActive !== '1') {
            return $this->response->setJSON([
                'success' => false,
                'type'    => 'disabled',
                'message' => 'Fitur absensi QR sedang dinonaktifkan.',
            ]);
        }

        // 1. Validasi jam operasional
        $now = date('H:i');
        if ($now < $scanStart || $now > $scanEnd) {
            return $this->response->setJSON([
                'success' => false,
                'type'    => 'outside_hours',
                'message' => "Di luar jam absensi ({$scanStart}–{$scanEnd}).",
            ]);
        }

        // 2. Cari siswa berdasarkan NISN
        $student = $this->studentModel->where('nisn', $nisn)->where('deleted_at', null)->first();
        if (!$student) {
            return $this->response->setJSON([
                'success' => false,
                'type'    => 'not_found',
                'message' => "NISN {$nisn} tidak ditemukan.",
            ]);
        }

        $today = date('Y-m-d');

        // 3. Cek duplikat
        if ($this->scanModel->alreadyScanned((int)$student['id'], $today)) {
            return $this->response->setJSON([
                'success' => false,
                'type'    => 'duplicate',
                'message' => "{$student['full_name']} sudah absen hari ini.",
                'student' => $this->buildStudentInfo($student),
            ]);
        }

        // 4. Ambil kelas aktif siswa
        $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        $classInfo = null;
        if ($activePeriod) {
            $classInfo = $db->table('student_academic_histories sah')
                ->select('sah.classroom_id, c.name as classroom_name, g.name as grade_name')
                ->join('classrooms c', 'c.id = sah.classroom_id', 'left')
                ->join('grades g', 'g.id = c.grade_id', 'left')
                ->where('sah.student_id', $student['id'])
                ->where('sah.academic_period_id', $activePeriod['id'])
                ->get()->getRowArray();
        }

        // 5. Simpan log scan
        $this->scanModel->logScan(
            (int)$student['id'],
            $today,
            date('H:i:s'),
            $this->request->getIPAddress()
        );

        return $this->response->setJSON([
            'success' => true,
            'type'    => 'ok',
            'message' => "Hadir dicatat.",
            'student' => array_merge($this->buildStudentInfo($student), [
                'classroom' => ($classInfo['grade_name'] ?? '') . ' ' . ($classInfo['classroom_name'] ?? '-'),
                'scan_time' => date('H:i:s'),
            ]),
            'count_today' => $this->scanModel->countToday($today),
        ]);
    }

    // ── AJAX: Status scan hari ini ───────────────────────────────
    public function getDailyStatus()
    {
        if (!$this->request->isAJAX()) {
            return $this->response->setStatusCode(403)->setJSON([]);
        }
        $today = date('Y-m-d');
        return $this->response->setJSON([
            'success'     => true,
            'count_today' => $this->scanModel->countToday($today),
            'today'       => $today,
        ]);
    }

    // ── Halaman rekap harian ─────────────────────────────────────
    public function dailyReport()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!$this->isBkOrAdmin()) {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak! Hanya Guru BK dan Admin.');
        }

        $date        = $this->request->getGet('date') ?: date('Y-m-d');
        $classroomId = (int)($this->request->getGet('classroom_id') ?? 0) ?: null;

        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null) {
            if ($classroomId) {
                if (!in_array($classroomId, $allowedIds)) {
                    return redirect()->to('/attendance/qr-report')->with('error', 'Akses ditolak! Anda tidak mengampu kelas ini.');
                }
            } else {
                if (!empty($allowedIds)) {
                    $classroomId = $allowedIds[0];
                } else {
                    $classroomId = -999;
                }
            }
        }

        $rows = $this->scanModel->getFullDailyReport($date, $classroomId);

        // Ringkasan per status
        $summary = ['hadir' => 0, 'Sakit' => 0, 'Izin' => 0, 'Alpha' => 0, 'belum' => 0];
        foreach ($rows as $r) {
            $k = $r['kehadiran'];
            if (isset($summary[$k])) $summary[$k]++;
            else $summary['belum']++;
        }

        // Daftar kelas (untuk filter dropdown)
        $db       = \Config\Database::connect();
        $period   = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        $classrooms = [];
        if ($period) {
            $classroomsQuery = $db->table('student_academic_histories sah')
                ->select('c.id, g.name as grade_name, c.name as classroom_name')
                ->join('classrooms c', 'c.id = sah.classroom_id')
                ->join('grades g',     'g.id = c.grade_id')
                ->where('sah.academic_period_id', $period['id']);

            if ($allowedIds !== null) {
                if (empty($allowedIds)) {
                    $classroomsQuery->where('1 = 0');
                } else {
                    $classroomsQuery->whereIn('c.id', $allowedIds);
                }
            }

            $classrooms = $classroomsQuery->groupBy('c.id')
                ->orderBy('g.order')->orderBy('c.name')
                ->get()->getResultArray();
        }

        return view('attendance/qr_report', [
            'title'       => 'Rekap Absensi Harian — ' . date('d M Y', strtotime($date)),
            'date'        => $date,
            'rows'        => $rows,
            'summary'     => $summary,
            'classrooms'  => $classrooms,
            'classroom_id' => $classroomId,
            'waGroupId'   => $classroomId ? $this->getClassroomWaGroupId($classroomId) : '',
        ]);
    }

    // ── Halaman pengaturan jam QR ────────────────────────────────
    public function settingsPage()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!in_array(session()->get('user_role'), ['superadmin', 'admin'])) {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');
        }

        $db   = \Config\Database::connect();
        $rows = $db->table('settings')
            ->whereIn('setting_key', ['qr_scan_start_time', 'qr_scan_end_time', 'qr_scan_active'])
            ->get()->getResultArray();

        $settings = [];
        foreach ($rows as $r) {
            $settings[$r['setting_key']] = $r['setting_value'];
        }

        return view('attendance/qr_settings', [
            'title'    => 'Pengaturan QR Scan',
            'settings' => $settings,
        ]);
    }

    // ── Simpan pengaturan jam QR ─────────────────────────────────
    public function saveSettings()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!in_array(session()->get('user_role'), ['superadmin', 'admin'])) {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');
        }

        $db   = \Config\Database::connect();
        $data = [
            'qr_scan_start_time' => $this->request->getPost('qr_scan_start_time') ?: '06:00',
            'qr_scan_end_time'   => $this->request->getPost('qr_scan_end_time')   ?: '08:00',
            'qr_scan_active'     => $this->request->getPost('qr_scan_active')     ?: '1',
        ];

        foreach ($data as $key => $value) {
            $exists = $db->table('settings')->where('setting_key', $key)->countAllResults();
            if ($exists) {
                $db->table('settings')->where('setting_key', $key)->update(['setting_value' => $value]);
            } else {
                $db->table('settings')->insert(['setting_key' => $key, 'setting_value' => $value]);
            }
        }

        return redirect()->to('/attendance/qr-settings')
            ->with('success', 'Pengaturan QR berhasil disimpan.');
    }

    // ── AJAX: Tandai Hadir Manual (Lupa Kartu) ────────────────────
    public function markPresentManual()
    {
        if ($this->checkLogin()) return $this->response->setStatusCode(403);
        if (!$this->isBkOrAdmin()) return $this->response->setStatusCode(403);

        $studentId = (int)$this->request->getPost('student_id');
        $date = $this->request->getPost('date') ?: date('Y-m-d');

        if (!$studentId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Siswa tidak valid.']);
        }

        // Validasi akses kelas siswa
        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null) {
            $db = \Config\Database::connect();
            $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
            if (!$activePeriod) {
                return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode aktif.']);
            }
            $studentClass = $db->table('student_academic_histories')
                ->select('classroom_id')
                ->where('student_id', $studentId)
                ->where('academic_period_id', $activePeriod['id'])
                ->get()
                ->getRowArray();
                
            if (!$studentClass || !in_array($studentClass['classroom_id'], $allowedIds)) {
                return $this->response->setJSON(['success' => false, 'message' => 'Akses ditolak! Anda tidak mengampu siswa ini.']);
            }
        }

        if ($this->scanModel->alreadyScanned($studentId, $date)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Siswa sudah hadir.']);
        }

        $success = $this->scanModel->logScan(
            $studentId,
            $date,
            '07:00:00', // waktu default override
            'override_bk'
        );

        return $this->response->setJSON([
            'success' => $success,
            'message' => $success ? 'Kehadiran berhasil dicatat.' : 'Gagal mencatat kehadiran.'
        ]);
    }

    // ── AJAX: Hadirkan Massal (Bulk Override) ─────────────────────
    public function markPresentBulk()
    {
        if ($this->checkLogin()) return $this->response->setStatusCode(403);
        if (!$this->isBkOrAdmin()) return $this->response->setStatusCode(403);

        $classroomId = (int)$this->request->getPost('classroom_id');
        $date = $this->request->getPost('date') ?: date('Y-m-d');

        if (!$classroomId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Kelas tidak valid.']);
        }

        // Validasi akses kelas
        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null && !in_array($classroomId, $allowedIds)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Akses ditolak! Anda tidak mengampu kelas ini.']);
        }

        $db = \Config\Database::connect();
        $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        if (!$activePeriod) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode aktif.']);
        }

        // Ambil semua siswa di kelas ini
        $students = $db->table('student_academic_histories sah')
            ->select('sah.student_id')
            ->where('sah.classroom_id', $classroomId)
            ->where('sah.academic_period_id', $activePeriod['id'])
            ->get()->getResultArray();

        $successCount = 0;
        foreach ($students as $s) {
            $sid = (int)$s['student_id'];
            
            // Cek apakah sudah ada status Sakit/Izin di attendances
            $hasExcusedAbsence = $db->table('attendances')
                ->where('student_id', $sid)
                ->where('date', $date)
                ->whereIn('status', ['Sakit', 'Izin'])
                ->countAllResults() > 0;

            if ($hasExcusedAbsence) {
                continue; // Jangan override yang sudah sakit/izin
            }

            if (!$this->scanModel->alreadyScanned($sid, $date)) {
                $this->scanModel->logScan($sid, $date, '07:00:00', 'override_bk_bulk');
                $successCount++;
            }
        }

        return $this->response->setJSON([
            'success' => true,
            'message' => "Berhasil menghadirkan {$successCount} siswa."
        ]);
    }

    // ── Rekap Bulanan QR ──────────────────────────────────────────
    public function qrRekapBulanan()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!$this->isBkOrAdmin()) {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');
        }

        $db = \Config\Database::connect();
        $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        if (!$activePeriod) {
            return redirect()->to('/dashboard')->with('error', 'Belum ada periode aktif!');
        }

        // List grades
        $gradeModel = new \App\Models\GradeModel();
        $grades = $gradeModel->orderBy('order', 'ASC')->findAll();

        $data = [
            'title'        => 'Rekap Absensi Bulanan QR',
            'activePeriod' => $activePeriod,
            'grades'       => $grades,
            'months'       => [
                1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April',
                5 => 'Mei', 6 => 'Juni', 7 => 'Juli', 8 => 'Agustus',
                9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember'
            ],
            'currentYear'  => date('Y')
        ];

        return view('attendance/qr_rekap_bulanan', $data);
    }

    // AJAX: Data Rekap Bulanan QR
    public function qrGetRekapBulanan()
    {
        if ($this->checkLogin()) return $this->response->setStatusCode(403);
        if (!$this->isBkOrAdmin()) return $this->response->setStatusCode(403);

        $classroomId = (int)$this->request->getGet('classroom_id');
        $periodId    = (int)$this->request->getGet('period_id');
        $month       = (int)$this->request->getGet('month');
        $year        = (int)$this->request->getGet('year');

        if (!$classroomId || !$periodId || !$month || !$year) {
            return $this->response->setJSON([]);
        }

        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null && !in_array($classroomId, $allowedIds)) {
            return $this->response->setJSON([]);
        }

        $db = \Config\Database::connect();
        $period = $db->table('academic_periods')->where('id', $periodId)->get()->getRowArray();
        if (!$period) return $this->response->setJSON([]);

        $startDate = "$year-$month-01";
        $endDate = date('Y-m-t', strtotime($startDate));
        $periodeStart = $period['start_date'];
        $periodeEnd = $period['end_date'];
        if ($startDate < $periodeStart) $startDate = $periodeStart;
        if ($endDate > $periodeEnd) $endDate = $periodeEnd;

        $attendanceModel = new \App\Models\AttendanceModel();
        $totalHariAktif = $attendanceModel->countActiveDays($startDate, $endDate);

        $holidayMap = [];
        $holidays = $db->table('calendar_events')
            ->select('calendar_events.start_date, calendar_events.end_date, calendar_events.title')
            ->join('calendar_categories', 'calendar_categories.id = calendar_events.category_id')
            ->where('calendar_categories.is_libur', 1)
            ->where('calendar_events.deleted_at', null)
            ->where('calendar_events.start_date <=', $endDate)
            ->where('calendar_events.end_date >=', $startDate)
            ->get()->getResultArray();

        foreach ($holidays as $h) {
            $start = strtotime($h['start_date']);
            $end = strtotime($h['end_date']);
            for ($curr = $start; $curr <= $end; $curr = strtotime('+1 day', $curr)) {
                $dateStr = date('Y-m-d', $curr);
                if ($dateStr >= $startDate && $dateStr <= $endDate) {
                    $holidayMap[$dateStr] = $h['title'];
                }
            }
        }

        $days = [];
        $daysInMonth = (int) date('t', strtotime($startDate));
        for ($d = 1; $d <= $daysInMonth; $d++) {
            $dateStr = sprintf('%s-%02d-%02d', $year, $month, $d);
            $dayOfWeek = date('N', strtotime($dateStr));
            $isSunday = ($dayOfWeek == 7);
            $isHoliday = isset($holidayMap[$dateStr]);
            $days[] = [
                'day' => $d,
                'is_off' => ($isSunday || $isHoliday),
                'holiday_title' => $holidayMap[$dateStr] ?? null,
            ];
        }

        $allStudents = $db->table('student_academic_histories sah')
            ->select('s.id, s.nis, s.full_name, s.gender')
            ->join('students s', 's.id = sah.student_id')
            ->where('sah.classroom_id', $classroomId)
            ->where('sah.academic_period_id', $periodId)
            ->where('s.deleted_at', null)
            ->where('s.status', 'Aktif')
            ->orderBy('s.full_name', 'ASC')
            ->get()->getResultArray();

        $qrScans = $db->table('qr_scan_logs')
            ->select('student_id, date')
            ->where('date >=', $startDate)
            ->where('date <=', $endDate)
            ->whereIn('student_id', array_column($allStudents, 'id'))
            ->get()->getResultArray();

        $qrMap = [];
        foreach ($qrScans as $qr) {
            $day = (int) date('j', strtotime($qr['date']));
            $qrMap[$qr['student_id']][$day] = true;
        }

        $attendancesRaw = $db->table('attendances')
            ->select('student_id, date, status')
            ->where('classroom_id', $classroomId)
            ->where('academic_period_id', $periodId)
            ->where('date >=', $startDate)
            ->where('date <=', $endDate)
            ->get()->getResultArray();

        $attDailyMap = [];
        foreach ($attendancesRaw as $a) {
            $day = (int) date('j', strtotime($a['date']));
            $attDailyMap[$a['student_id']][$day] = $a['status'];
        }

        $result = [];
        foreach ($allStudents as $student) {
            $sId = $student['id'];
            $sakit = $izin = $alpha = $hadir = 0;
            $statuses = [];

            for ($d = 1; $d <= $daysInMonth; $d++) {
                $dateStr = sprintf('%s-%02d-%02d', $year, $month, $d);
                $dayOfWeek = date('N', strtotime($dateStr));
                $isOff = ($dayOfWeek == 7 || isset($holidayMap[$dateStr]));

                if ($isOff) {
                    $statuses[$d] = '';
                    continue;
                }

                $attStatus = $attDailyMap[$sId][$d] ?? null;
                if ($attStatus === 'Sakit') {
                    $statuses[$d] = 'S';
                    $sakit++;
                } elseif ($attStatus === 'Izin') {
                    $statuses[$d] = 'I';
                    $izin++;
                } elseif ($attStatus === 'Alpha') {
                    $statuses[$d] = 'A';
                    $alpha++;
                } elseif (isset($qrMap[$sId][$d])) {
                    $statuses[$d] = '.';
                    $hadir++;
                } else {
                    $statuses[$d] = 'A';
                    $alpha++;
                }
            }

            $result[] = [
                'nis' => $student['nis'],
                'full_name' => $student['full_name'],
                'gender' => $student['gender'],
                'sakit' => $sakit,
                'izin' => $izin,
                'alpha' => $alpha,
                'hadir' => $hadir,
                'total_hari' => $totalHariAktif,
                'statuses' => $statuses,
            ];
        }

        return $this->response->setJSON([
            'success' => true,
            'students' => $result,
            'days' => $days,
            'total_hari_aktif' => $totalHariAktif,
            'bulan' => $month,
            'tahun' => $year,
        ]);
    }

    // ── Rekap Semester QR ─────────────────────────────────────────
    public function qrRekapSemester()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!$this->isBkOrAdmin()) {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');
        }

        $db = \Config\Database::connect();
        $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        if (!$activePeriod) {
            return redirect()->to('/dashboard')->with('error', 'Belum ada periode aktif!');
        }

        // List grades
        $gradeModel = new \App\Models\GradeModel();
        $grades = $gradeModel->orderBy('order', 'ASC')->findAll();

        // List period
        $periodModel = new \App\Models\AcademicPeriodModel();
        $periods = $periodModel->getAllWithYear();

        $data = [
            'title'        => 'Rekap Absensi Semester QR',
            'activePeriod' => $activePeriod,
            'grades'       => $grades,
            'periods'      => $periods,
        ];

        return view('attendance/qr_rekap_semester', $data);
    }

    // AJAX: Data Rekap Semester QR
    public function qrGetRekapSemester()
    {
        if ($this->checkLogin()) return $this->response->setStatusCode(403);
        if (!$this->isBkOrAdmin()) return $this->response->setStatusCode(403);

        $classroomId = (int)$this->request->getGet('classroom_id');
        $periodId    = (int)$this->request->getGet('period_id');

        if (!$classroomId || !$periodId) {
            return $this->response->setJSON([]);
        }

        // Validasi akses kelas
        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null && !in_array($classroomId, $allowedIds)) {
            return $this->response->setJSON([]);
        }

        $db = \Config\Database::connect();
        $period = $db->table('academic_periods')->where('id', $periodId)->get()->getRowArray();
        if (!$period) return $this->response->setJSON([]);

        // Hitung total hari aktif
        $attendanceModel = new \App\Models\AttendanceModel();
        $totalHariAktif = $attendanceModel->countActiveDays($period['start_date'], $period['end_date']);

        $rekap = $this->scanModel->getQrSemesterRecap($classroomId, $periodId);

        $result = [];
        foreach ($rekap as $row) {
            $sakit = (int)$row['sakit'];
            $izin = (int)$row['izin'];
            $hadir = (int)$row['hadir'];
            $alpha = max(0, $totalHariAktif - ($hadir + $sakit + $izin));

            $result[] = [
                'nis' => $row['nis'],
                'full_name' => $row['full_name'],
                'sakit' => $sakit,
                'izin' => $izin,
                'alpha' => $alpha,
                'total_hari' => $totalHariAktif
            ];
        }

        return $this->response->setJSON([
            'success' => true,
            'students' => $result,
            'total_hari_aktif' => $totalHariAktif
        ]);
    }

    // ── Export PDF Rekap Bulanan QR ───────────────────────────────
    public function qrExportPdfBulanan()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!$this->isBkOrAdmin()) return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');

        $classroomId = (int)$this->request->getGet('classroom_id');
        $periodId    = (int)$this->request->getGet('period_id');
        $month       = (int)$this->request->getGet('month');
        $year        = (int)$this->request->getGet('year');

        if (!$classroomId || !$periodId || !$month || !$year) {
            return redirect()->back()->with('error', 'Data tidak lengkap!');
        }

        // Validasi akses kelas
        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null && !in_array($classroomId, $allowedIds)) {
            return redirect()->back()->with('error', 'Akses ditolak! Anda tidak mengampu kelas ini.');
        }

        $db = \Config\Database::connect();
        $period = $db->table('academic_periods')->where('id', $periodId)->get()->getRowArray();
        if (!$period) return redirect()->back()->with('error', 'Periode tidak valid.');

        $classroomModel = new \App\Models\ClassroomModel();
        $classroom = $classroomModel->find($classroomId);
        $gradeModel = new \App\Models\GradeModel();
        $grade = $gradeModel->find($classroom['grade_id']);

        // Info kepala sekolah & wali kelas
        $settingModel = new \App\Models\SchoolSettingModel();
        $setting = $settingModel->getSettings();
        $kepalaSekolah = [
            'name' => $setting['principal_name'] ?? '',
            'nip' => $setting['principal_nip'] ?? '',
            'city' => $setting['city'] ?? 'Wonogiri'
        ];
        
        $bkAssignment = $db->table('bk_assignments')
            ->select('teachers.name as teacher_name, teachers.nip as teacher_nip')
            ->join('teachers', 'teachers.id = bk_assignments.teacher_id')
            ->where('bk_assignments.classroom_id', $classroomId)
            ->where('bk_assignments.academic_period_id', $periodId)
            ->get()->getRowArray();
        
        $waliKelas = $bkAssignment ?? [
            'teacher_name' => '_________________________',
            'teacher_nip' => ''
        ];

        // Hitung total hari aktif
        $startDate = "$year-$month-01";
        $endDate = date('Y-m-t', strtotime($startDate));
        $periodeStart = $period['start_date'];
        $periodeEnd = $period['end_date'];
        if ($startDate < $periodeStart) $startDate = $periodeStart;
        if ($endDate > $periodeEnd) $endDate = $periodeEnd;
        $attendanceModel = new \App\Models\AttendanceModel();
        $totalHariAktif = $attendanceModel->countActiveDays($startDate, $endDate);

        $holidayMap = [];
        $holidays = $db->table('calendar_events')
            ->select('calendar_events.start_date, calendar_events.end_date, calendar_events.title')
            ->join('calendar_categories', 'calendar_categories.id = calendar_events.category_id')
            ->where('calendar_categories.is_libur', 1)
            ->where('calendar_events.deleted_at', null)
            ->where('calendar_events.start_date <=', $endDate)
            ->where('calendar_events.end_date >=', $startDate)
            ->get()->getResultArray();

        foreach ($holidays as $h) {
            $start = strtotime($h['start_date']);
            $end = strtotime($h['end_date']);
            for ($curr = $start; $curr <= $end; $curr = strtotime('+1 day', $curr)) {
                $dateStr = date('Y-m-d', $curr);
                if ($dateStr >= $startDate && $dateStr <= $endDate) {
                    $holidayMap[$dateStr] = $h['title'];
                }
            }
        }

        $days = [];
        $daysInMonth = (int) date('t', strtotime($startDate));
        for ($d = 1; $d <= $daysInMonth; $d++) {
            $dateStr = sprintf('%s-%02d-%02d', $year, $month, $d);
            $dayOfWeek = date('N', strtotime($dateStr));
            $isSunday = ($dayOfWeek == 7);
            $isHoliday = isset($holidayMap[$dateStr]);
            $days[] = [
                'day' => $d,
                'is_off' => ($isSunday || $isHoliday),
                'holiday_title' => $holidayMap[$dateStr] ?? null,
            ];
        }

        $allStudents = $db->table('student_academic_histories sah')
            ->select('s.id, s.nis, s.full_name, s.gender')
            ->join('students s', 's.id = sah.student_id')
            ->where('sah.classroom_id', $classroomId)
            ->where('sah.academic_period_id', $periodId)
            ->where('s.deleted_at', null)
            ->where('s.status', 'Aktif')
            ->orderBy('s.full_name', 'ASC')
            ->get()->getResultArray();

        $qrScans = $db->table('qr_scan_logs')
            ->select('student_id, date')
            ->where('date >=', $startDate)
            ->where('date <=', $endDate)
            ->whereIn('student_id', array_column($allStudents, 'id'))
            ->get()->getResultArray();

        $qrMap = [];
        foreach ($qrScans as $qr) {
            $day = (int) date('j', strtotime($qr['date']));
            $qrMap[$qr['student_id']][$day] = true;
        }

        $attendancesRaw = $db->table('attendances')
            ->select('student_id, date, status')
            ->where('classroom_id', $classroomId)
            ->where('academic_period_id', $periodId)
            ->where('date >=', $startDate)
            ->where('date <=', $endDate)
            ->get()->getResultArray();

        $attDailyMap = [];
        foreach ($attendancesRaw as $a) {
            $day = (int) date('j', strtotime($a['date']));
            $attDailyMap[$a['student_id']][$day] = $a['status'];
        }

        $dataSiswa = [];
        $totalS = $totalI = $totalA = $totalH = 0;
        foreach ($allStudents as $student) {
            $sId = $student['id'];
            $sakit = $izin = $alpha = $hadir = 0;
            $statuses = [];

            for ($d = 1; $d <= $daysInMonth; $d++) {
                $dateStr = sprintf('%s-%02d-%02d', $year, $month, $d);
                $dayOfWeek = date('N', strtotime($dateStr));
                $isOff = ($dayOfWeek == 7 || isset($holidayMap[$dateStr]));

                if ($isOff) {
                    $statuses[$d] = '';
                    continue;
                }

                $attStatus = $attDailyMap[$sId][$d] ?? null;
                if ($attStatus === 'Sakit') {
                    $statuses[$d] = 'S';
                    $sakit++;
                } elseif ($attStatus === 'Izin') {
                    $statuses[$d] = 'I';
                    $izin++;
                } elseif ($attStatus === 'Alpha') {
                    $statuses[$d] = 'A';
                    $alpha++;
                } elseif (isset($qrMap[$sId][$d])) {
                    $statuses[$d] = '.';
                    $hadir++;
                } else {
                    $statuses[$d] = 'A';
                    $alpha++;
                }
            }

            $totalS += $sakit;
            $totalI += $izin;
            $totalA += $alpha;
            $totalH += $hadir;

            $dataSiswa[] = [
                'nis' => $student['nis'],
                'full_name' => $student['full_name'],
                'gender' => $student['gender'],
                'sakit' => $sakit,
                'izin' => $izin,
                'alpha' => $alpha,
                'hadir' => $hadir,
                'statuses' => $statuses,
            ];
        }

        $namaBulan = ['Januari', 'Februari', 'Maret', 'April', 'Mei', 'Juni', 'Juli', 'Agustus', 'September', 'Oktober', 'November', 'Desember'];

        $data = [
            'judul' => 'REKAP ABSENSI BULANAN QR CODE',
            'subjudul' => 'Bulan: ' . $namaBulan[(int)$month - 1] . ' ' . $year,
            'kelas' => ['name' => $classroom['name'], 'level' => $grade['name']],
            'dataSiswa' => $dataSiswa,
            'days' => $days,
            'totalS' => $totalS,
            'totalI' => $totalI,
            'totalA' => $totalA,
            'totalH' => $totalH,
            'totalSiswa' => count($dataSiswa),
            'kepalaSekolah' => $kepalaSekolah,
            'waliKelas' => $waliKelas,
        ];

        return view('attendance/qr_export_pdf_bulanan', $data);
    }

    // ── Export PDF Rekap Semester QR ──────────────────────────────
    public function qrExportPdfSemester()
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if (!$this->isBkOrAdmin()) return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');

        $classroomId = (int)$this->request->getGet('classroom_id');
        $periodId    = (int)$this->request->getGet('period_id');

        if (!$classroomId || !$periodId) {
            return redirect()->back()->with('error', 'Data tidak lengkap!');
        }

        // Validasi akses kelas
        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null && !in_array($classroomId, $allowedIds)) {
            return redirect()->back()->with('error', 'Akses ditolak! Anda tidak mengampu kelas ini.');
        }

        $db = \Config\Database::connect();
        $period = $db->table('academic_periods')->where('id', $periodId)->get()->getRowArray();
        if (!$period) return redirect()->back()->with('error', 'Periode tidak valid.');

        $classroomModel = new \App\Models\ClassroomModel();
        $classroom = $classroomModel->find($classroomId);
        $gradeModel = new \App\Models\GradeModel();
        $grade = $gradeModel->find($classroom['grade_id']);

        $academicYear = $db->table('academic_years')->select('name')->where('id', $period['academic_year_id'])->get()->getRowArray();

        // Info kepala sekolah & wali kelas
        $settingModel = new \App\Models\SchoolSettingModel();
        $setting = $settingModel->getSettings();
        $kepalaSekolah = [
            'name' => $setting['principal_name'] ?? '',
            'nip' => $setting['principal_nip'] ?? '',
            'city' => $setting['city'] ?? 'Wonogiri'
        ];
        
        $bkAssignment = $db->table('bk_assignments')
            ->select('teachers.name as teacher_name, teachers.nip as teacher_nip')
            ->join('teachers', 'teachers.id = bk_assignments.teacher_id')
            ->where('bk_assignments.classroom_id', $classroomId)
            ->where('bk_assignments.academic_period_id', $periodId)
            ->get()->getRowArray();
        
        $waliKelas = $bkAssignment ?? [
            'teacher_name' => '_________________________',
            'teacher_nip' => ''
        ];

        // Hitung total hari aktif
        $attendanceModel = new \App\Models\AttendanceModel();
        $totalHariAktif = $attendanceModel->countActiveDays($period['start_date'], $period['end_date']);

        // Data rekap
        $rekap = $this->scanModel->getQrSemesterRecap($classroomId, $periodId);

        $dataSiswa = [];
        $grandTotalA = $grandTotalI = $grandTotalS = 0;
        foreach ($rekap as $row) {
            $sakit = (int)$row['sakit'];
            $izin = (int)$row['izin'];
            $hadir = (int)$row['hadir'];
            $alpha = max(0, $totalHariAktif - ($hadir + $sakit + $izin));

            $grandTotalA += $alpha;
            $grandTotalI += $izin;
            $grandTotalS += $sakit;

            $std = $db->table('students')->select('gender')->where('id', $row['student_id'])->get()->getRowArray();

            $dataSiswa[] = [
                'nis' => $row['nis'],
                'full_name' => $row['full_name'],
                'gender' => $std['gender'] ?? '-',
                'alpha' => $alpha,
                'izin' => $izin,
                'sakit' => $sakit,
                'total' => $alpha + $izin + $sakit
            ];
        }

        $data = [
            'judul' => 'REKAP ABSENSI SEMESTER QR CODE',
            'subjudul' => 'Periode: ' . $period['semester'] . ' - ' . ($academicYear['name'] ?? ''),
            'kelas' => ['name' => $classroom['name'], 'level' => $grade['name']],
            'dataSiswa' => $dataSiswa,
            'grandTotalA' => $grandTotalA,
            'grandTotalI' => $grandTotalI,
            'grandTotalS' => $grandTotalS,
            'totalSiswa' => count($dataSiswa),
            'totalHariAktif' => $totalHariAktif,
            'kepalaSekolah' => $kepalaSekolah,
            'waliKelas' => $waliKelas,
        ];

        return view('attendance/qr_export_pdf_semester', $data);
    }

    // ── Helper ──────────────────────────────────────────────────
    private function checkLogin()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }
        return null;
    }

    // ── AJAX: Simpan Status Kehadiran Manual dari Laporan QR ──────────────────
    public function saveStatusManual()
    {
        if ($this->checkLogin()) return $this->response->setStatusCode(403);
        if (!$this->isBkOrAdmin()) return $this->response->setStatusCode(403);

        $studentId = (int)$this->request->getPost('student_id');
        $date = $this->request->getPost('date') ?: date('Y-m-d');
        $status = $this->request->getPost('status'); // 'hadir', 'Sakit', 'Izin', 'Alpha', 'belum'

        if (!$studentId || !$status) {
            return $this->response->setJSON(['success' => false, 'message' => 'Data tidak lengkap.']);
        }

        $db = \Config\Database::connect();
        $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
        if (!$activePeriod) {
            return $this->response->setJSON(['success' => false, 'message' => 'Tidak ada periode akademik aktif.']);
        }
        $periodId = $activePeriod['id'];

        // Ambil info classroom
        $history = $db->table('student_academic_histories')
            ->where('student_id', $studentId)
            ->where('academic_period_id', $periodId)
            ->get()->getRowArray();
        if (!$history) {
            return $this->response->setJSON(['success' => false, 'message' => 'Siswa tidak memiliki kelas aktif.']);
        }
        $classroomId = $history['classroom_id'];

        // Validasi akses kelas
        $allowedIds = $this->getAllowedClassroomIds();
        if ($allowedIds !== null && !in_array($classroomId, $allowedIds)) {
            return $this->response->setJSON(['success' => false, 'message' => 'Akses ditolak! Anda tidak mengampu kelas ini.']);
        }

        $attendanceModel = new \App\Models\AttendanceModel();
        // attendances.recorded_by references users.id, not the display name.
        $userId = session()->get('user_id');

        $db->transStart();

        if ($status === 'hadir') {
            // Hapus dari attendances (karena hadir)
            $db->table('attendances')
                ->where('student_id', $studentId)
                ->where('date', $date)
                ->where('academic_period_id', $periodId)
                ->delete();

            // Tambahkan ke qr_scan_logs jika belum ada
            if (!$this->scanModel->alreadyScanned($studentId, $date)) {
                $this->scanModel->logScan($studentId, $date, '07:00:00', 'override_bk');
            }
        } elseif (in_array($status, ['Sakit', 'Izin', 'Alpha'])) {
            // Hapus dari qr_scan_logs
            $db->table('qr_scan_logs')
                ->where('student_id', $studentId)
                ->where('date', $date)
                ->delete();

            // Simpan ke attendances
            $attendanceModel->saveAttendance($studentId, $classroomId, $periodId, $date, $status, $userId);
        } elseif ($status === 'belum') {
            // Hapus dari qr_scan_logs
            $db->table('qr_scan_logs')
                ->where('student_id', $studentId)
                ->where('date', $date)
                ->delete();

            // Hapus dari attendances
            $db->table('attendances')
                ->where('student_id', $studentId)
                ->where('date', $date)
                ->where('academic_period_id', $periodId)
                ->delete();
        } else {
            $db->transRollback();
            return $this->response->setJSON(['success' => false, 'message' => 'Status tidak dikenali.']);
        }

        $db->transComplete();

        if ($db->transStatus() === false) {
            return $this->response->setJSON(['success' => false, 'message' => 'Gagal memperbarui status.']);
        }

        return $this->response->setJSON([
            'success' => true,
            'message' => 'Status kehadiran berhasil diperbarui.'
        ]);
    }

    private function getAllowedClassroomIds(): ?array
    {
        $role = session()->get('user_role');
        
        if (in_array($role, ['superadmin', 'admin'])) {
            return null; // Bebas akses semua kelas
        }
        
        if ($role == 'guru') {
            $userId = session()->get('user_id');
            $db = \Config\Database::connect();
            
            $teacher = $db->table('teachers')
                          ->select('id')
                          ->where('user_id', $userId)
                          ->get()
                          ->getRowArray();
                          
            if ($teacher) {
                $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
                if ($activePeriod) {
                    $assignments = $db->table('bk_assignments')
                                      ->select('classroom_id')
                                      ->where('teacher_id', $teacher['id'])
                                      ->where('academic_period_id', $activePeriod['id'])
                                      ->get()
                                      ->getResultArray();
                                      
                    return array_column($assignments, 'classroom_id');
                }
            }
        }
        
        return []; // Default tidak boleh akses kelas mana pun
    }

    private function isBkOrAdmin()
    {
        $role = session()->get('user_role');
        if (in_array($role, ['superadmin', 'admin'])) {
            return true;
        }
        
        if ($role == 'guru') {
            $userId = session()->get('user_id');
            $db = \Config\Database::connect();
            $teacher = $db->table('teachers')->select('id')->where('user_id', $userId)->get()->getRowArray();
            if ($teacher) {
                $activePeriod = $db->table('academic_periods')->where('is_active', 1)->get()->getRowArray();
                if ($activePeriod) {
                    $bkAssignment = $db->table('bk_assignments')
                                    ->where('teacher_id', $teacher['id'])
                                    ->where('academic_period_id', $activePeriod['id'])
                                    ->get()
                                    ->getRowArray();
                    if ($bkAssignment) {
                        return true;
                    }
                }
            }
        }
        return false;
    }

    private function buildStudentInfo(array $student): array
    {
        return [
            'id'        => $student['id'],
            'nisn'      => $student['nisn'],
            'nis'       => $student['nis'],
            'full_name' => $student['full_name'],
            'gender'    => $student['gender'],
        ];
    }

    private function getClassroomWaGroupId($classroomId)
    {
        $db = \Config\Database::connect();
        $row = $db->table('settings')
            ->where('setting_key', 'wa_group_id_classroom_' . $classroomId)
            ->get()->getRowArray();
        return $row['setting_value'] ?? '';
    }

    public function sendWaGrup()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $waService = new \App\Services\WhatsappService();
        if (!$waService->isConfigured()) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'WhatsApp belum dikonfigurasi.',
            ]);
        }

        $classroomId = $this->request->getPost('classroom_id');
        $date        = $this->request->getPost('date') ?: date('Y-m-d');

        if (!$classroomId) {
            return $this->response->setJSON(['success' => false, 'message' => 'Pilih kelas terlebih dahulu.']);
        }

        $waGroupId = $this->getClassroomWaGroupId($classroomId);
        if (empty($waGroupId)) {
            return $this->response->setJSON(['success' => false, 'message' => 'ID Grup WhatsApp belum diatur untuk kelas ini.']);
        }

        $db = \Config\Database::connect();
        $classroom = $db->table('classrooms c')
            ->select('c.name, g.name as grade_name')
            ->join('grades g', 'g.id = c.grade_id')
            ->where('c.id', $classroomId)
            ->get()->getRowArray();

        if (!$classroom) {
            return $this->response->setJSON(['success' => false, 'message' => 'Kelas tidak ditemukan.']);
        }

        $rows = $this->scanModel->getFullDailyReport($date, $classroomId);

        $byStatus = ['hadir' => [], 'Sakit' => [], 'Izin' => [], 'Alpha' => [], 'belum' => []];
        foreach ($rows as $r) {
            $k = $r['kehadiran'];
            if (!isset($byStatus[$k])) $k = 'belum';
            $byStatus[$k][] = $r;
        }

        $total = count($rows);
        $hadir = count($byStatus['hadir']);
        $sakit = count($byStatus['Sakit']);
        $izin  = count($byStatus['Izin']);
        $alpha = count($byStatus['Alpha']);
        $belum = count($byStatus['belum']);

        $tanggal = date('l, d M Y', strtotime($date));
        $hariIndo = [
            'Monday' => 'Senin', 'Tuesday' => 'Selasa', 'Wednesday' => 'Rabu',
            'Thursday' => 'Kamis', 'Friday' => 'Jumat', 'Saturday' => 'Sabtu', 'Sunday' => 'Minggu',
        ];
        $tanggal = strtr($tanggal, $hariIndo);

        $schoolSettings = $db->table('school_settings')
            ->select('school_name')
            ->get()
            ->getRowArray();
        $schoolName = $schoolSettings['school_name'] ?? 'Sekolah';

        $msg = "📊 *REKAP ABSENSI HARIAN*\n"
            . "🏫 {$schoolName}\n"
            . "📅 {$tanggal}\n\n"
            . "📋 *Kelas {$classroom['grade_name']} {$classroom['name']}*\n\n"
            . "✅ Hadir  : {$hadir}\n"
            . "🤒 Sakit  : {$sakit}"
            . ($sakit > 0 ? ' — ' . implode(', ', array_column($byStatus['Sakit'], 'full_name')) : '') . "\n"
            . "📝 Izin   : {$izin}"
            . ($izin > 0 ? ' — ' . implode(', ', array_column($byStatus['Izin'], 'full_name')) : '') . "\n"
            . "❌ Alpha  : {$alpha}"
            . ($alpha > 0 ? ' — ' . implode(', ', array_column($byStatus['Alpha'], 'full_name')) : '') . "\n"
            . "⏳ Belum  : {$belum}"
            . ($belum > 0 ? ' — ' . implode(', ', array_column($byStatus['belum'], 'full_name')) : '') . "\n\n"
            . "Total Siswa: {$total}\n\n"
            . "Dikirim oleh petugas";

        try {
            $result = $waService->send($waGroupId, $msg, true);
            if (!$result['success']) {
                log_message('error', 'AttendanceQr::sendWaGrup - Gagal kirim rekap absensi ke grup ' . $waGroupId . ' kelas ' . $classroomId . '. Alasan: ' . $result['message']);
                return $this->response->setJSON([
                    'success' => false,
                    'message' => 'Gagal mengirim ke grup WA: ' . $result['message'],
                ]);
            }

            log_message('info', 'AttendanceQr::sendWaGrup - Berhasil kirim rekap absensi ke grup ' . $waGroupId . ' kelas ' . $classroomId . '.');
            return $this->response->setJSON([
                'success' => true,
                'message' => "Rekap absensi berhasil dikirim ke grup WA kelas {$classroom['grade_name']} {$classroom['name']}.",
            ]);
        } catch (\Exception $e) {
            log_message('error', 'AttendanceQr::sendWaGrup - Exception: ' . $e->getMessage());
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Gagal mengirim: ' . $e->getMessage(),
            ]);
        }
    }
}
