<?php

namespace App\Models;

use CodeIgniter\Model;

class AttendanceModel extends Model
{
    protected $table            = 'attendances';
    protected $primaryKey       = 'id';
    protected $useAutoIncrement = true;
    protected $returnType       = 'array';
    protected $useSoftDeletes   = false;
    protected $allowedFields    = [
        'student_id', 'classroom_id', 'academic_period_id', 'date', 'status', 'recorded_by'
    ];

    protected $useTimestamps = true;
    protected $createdField  = 'created_at';
    protected $updatedField  = 'updated_at';

    protected $beforeInsert = ['checkPeriodIsActive'];
    protected $beforeUpdate = ['checkPeriodIsActive'];
    protected $beforeDelete = ['checkPeriodIsActiveDelete'];

    protected function checkPeriodIsActive(array $data)
    {
        // Bypass for superadmin / admin (jika dibutuhkan, bisa dicek lewat session, 
        // tapi sesuai requirement: "Write-Protection for historic data in closed academic periods" berlaku umum)
        $periodId = $data['data']['academic_period_id'] ?? null;
        if (!$periodId && isset($data['id'])) {
            $record = $this->find($data['id'][0] ?? $data['id']);
            $periodId = $record['academic_period_id'] ?? null;
        }

        if ($periodId && !is_period_active($periodId)) {
            // Cek jika user login adalah superadmin / admin, izinkan bypass
            $role = session()->get('user_role');
            if (!in_array($role, ['superadmin', 'admin'])) {
                throw new \RuntimeException('Periode akademik ini telah ditutup. Data tidak dapat diubah!');
            }
        }

        return $data;
    }

    protected function checkPeriodIsActiveDelete(array $data)
    {
        $id = $data['id'][0] ?? $data['id'] ?? null;
        if ($id) {
            $record = $this->find($id);
            $periodId = $record['academic_period_id'] ?? null;
            if ($periodId && !is_period_active($periodId)) {
                $role = session()->get('user_role');
                if (!in_array($role, ['superadmin', 'admin'])) {
                    throw new \RuntimeException('Periode akademik ini telah ditutup. Data tidak dapat dihapus!');
                }
            }
        }
        return $data;
    }

    // Ambil absensi per kelas per tanggal
    public function getByClassroomAndDate($classroomId, $periodId, $date)
    {
        return $this->select('
                attendances.*,
                students.nis,
                students.nisn,
                students.full_name,
                students.gender
            ')
            ->join('students', 'students.id = attendances.student_id')
            ->where('attendances.classroom_id', $classroomId)
            ->where('attendances.academic_period_id', $periodId)
            ->where('attendances.date', $date)
            ->where('students.deleted_at', null)
            ->where('students.status', 'Aktif')
            ->orderBy('students.full_name', 'ASC')
            ->findAll();
    }

    // Ambil absensi untuk rekap bulanan
    public function getMonthlyRecap($classroomId, $periodId, $month, $year)
    {
        $startDate = "$year-$month-01";
        $endDate = date('Y-m-t', strtotime($startDate));
        
        return $this->select('
                students.id as student_id,
                students.nis,
                students.full_name,
                SUM(CASE WHEN attendances.status = "Sakit" THEN 1 ELSE 0 END) as sakit,
                SUM(CASE WHEN attendances.status = "Izin" THEN 1 ELSE 0 END) as izin,
                SUM(CASE WHEN attendances.status = "Alpha" THEN 1 ELSE 0 END) as alpha
            ')
            ->join('students', 'students.id = attendances.student_id')
            ->where('attendances.classroom_id', $classroomId)
            ->where('attendances.academic_period_id', $periodId)
            ->where('attendances.date >=', $startDate)
            ->where('attendances.date <=', $endDate)
            ->where('students.deleted_at', null)
            ->where('students.status', 'Aktif')
            ->groupBy('students.id')
            ->orderBy('students.full_name', 'ASC')
            ->findAll();
    }

    // Ambil absensi untuk rekap semester
    public function getSemesterRecap($classroomId, $periodId)
    {
        // Ambil tanggal start dan end dari periode
        $period = db_connect()->table('academic_periods')
                ->select('academic_periods.start_date, academic_periods.end_date')
                ->where('academic_periods.id', $periodId)
                ->get()
                ->getRowArray();
        
        if (!$period) return [];
        
        return $this->select('
                students.id as student_id,
                students.nis,
                students.full_name,
                SUM(CASE WHEN attendances.status = "Sakit" THEN 1 ELSE 0 END) as sakit,
                SUM(CASE WHEN attendances.status = "Izin" THEN 1 ELSE 0 END) as izin,
                SUM(CASE WHEN attendances.status = "Alpha" THEN 1 ELSE 0 END) as alpha
            ')
            ->join('students', 'students.id = attendances.student_id')
            ->where('attendances.classroom_id', $classroomId)
            ->where('attendances.academic_period_id', $periodId)
            ->where('attendances.date >=', $period['start_date'])
            ->where('attendances.date <=', $period['end_date'])
            ->where('students.deleted_at', null)
            ->where('students.status', 'Aktif')
            ->groupBy('students.id')
            ->orderBy('students.full_name', 'ASC')
            ->findAll();
    }

    // Simpan atau update absensi (upsert)
    public function saveAttendance($studentId, $classroomId, $periodId, $date, $status, $recordedBy)
    {
        $existing = $this->where('student_id', $studentId)
                         ->where('date', $date)
                         ->where('academic_period_id', $periodId)
                         ->first();
        
        if ($existing) {
            if ($status === null) {
                // Hapus record (berarti Hadir)
                return $this->delete($existing['id']);
            } else {
                // Update status
                return $this->update($existing['id'], [
                    'status' => $status,
                    'recorded_by' => $recordedBy,
                ]);
            }
        } else {
            if ($status !== null) {
                // Insert baru
                return $this->insert([
                    'student_id' => $studentId,
                    'classroom_id' => $classroomId,
                    'academic_period_id' => $periodId,
                    'date' => $date,
                    'status' => $status,
                    'recorded_by' => $recordedBy,
                ]);
            }
        }
        return true;
    }

    // Hitung total hari aktif (exclude weekend dan hari libur kalender akademik) dalam range tanggal
    public function countActiveDays($startDate, $endDate)
    {
        $db = \Config\Database::connect();
        
        // 1. Ambil pengaturan sabtu_libur
        $setting = $db->table('calendar_settings')->where('key', 'sabtu_libur')->get()->getRowArray();
        $sabtuLibur = $setting && (int)$setting['value'] === 1;

        // 2. Ambil daftar tanggal libur dari kalender akademik (is_libur = 1)
        $events = $db->table('calendar_events')
            ->select('calendar_events.start_date, calendar_events.end_date')
            ->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();

        $holidayDates = [];
        foreach ($events as $e) {
            $current = strtotime($e['start_date']);
            $last = strtotime($e['end_date']);
            while ($current <= $last) {
                $holidayDates[date('Y-m-d', $current)] = true;
                $current = strtotime('+1 day', $current);
            }
        }

        // 3. Hitung hari efektif
        $start = new \DateTime($startDate);
        $end = new \DateTime($endDate);
        $end->modify('+1 day');
        
        $interval = new \DateInterval('P1D');
        $period = new \DatePeriod($start, $interval, $end);
        
        $activeDays = 0;
        foreach ($period as $date) {
            $formattedDate = $date->format('Y-m-d');
            $dayOfWeek = (int) $date->format('N'); // 1=Senin, 7=Minggu
            
            // Hari Minggu selalu libur
            if ($dayOfWeek === 7) {
                continue;
            }
            
            // Hari Sabtu libur jika diatur sabtu_libur = 1
            if ($dayOfWeek === 6 && $sabtuLibur) {
                continue;
            }
            
            // Tanggal tersebut masuk dalam daftar libur kalender akademik
            if (isset($holidayDates[$formattedDate])) {
                continue;
            }
            
            $activeDays++;
        }
        
        return $activeDays;
    }
}