<?php

namespace App\Models;

use CodeIgniter\Model;

class AttendanceDataModel extends Model
{
    protected $table = 'attendance_data';
    protected $primaryKey = 'id';
    protected $useAutoIncrement = true;

    protected $allowedFields = [
        'class_id',         
        'class_section_id',
        'school_id',
        'student_id',
        'date',
        'status',
        'reason',
        'is_reported',          
        'is_notified',      
        'semester',
        'school_year',
        'modified_by',
        'created_at',
        'updated_at'
    ];

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

    private ?array $reportedColumns = null;

    protected $validationRules = [
        'class_id'        => 'required|is_natural_no_zero',
        'class_section_id'=> 'required|is_natural_no_zero',
        'student_id'      => 'required|is_natural_no_zero',
        'status'          => 'required|in_list[present,absent,late]',
        'is_reported'     => 'required|in_list[no,yes]',
        'is_notified'     => 'required|in_list[no,yes]',
        'date'            => 'required|valid_date[Y-m-d]',
        'semester'        => 'required',
        'school_year'     => 'required',
    ];
    /**
     * Retrieve attendance by class and section for a specific date.
     *
     * @param int $classId
     * @param int $classSectionId
     * @param string $date
     * @return array
     */
    public function getAttendanceByClass($classId, $classSectionId, $date)
    {
        return $this->where([
            'class_id' => $classId,
            'class_section_id' => $classSectionId,
            'date' => $date
        ])->findAll();
    }

    public function unreportedTermRows(array $studentIds, string $schoolYear, ?string $semester): array
{
    $qb = $this->builder()
        ->select('id, student_id, class_id, class_section_id, date, status, reason, school_year, semester, is_reported')
        ->where('school_year', $schoolYear);

    if ($semester !== null && $semester !== '') {
        $qb->where('semester', $semester);
    }
    if (!empty($studentIds)) {
        $qb->whereIn('student_id', $studentIds);
    }

    $this->applyUnreportedFilter($qb);

    return $qb->orderBy('date', 'DESC')->get()->getResultArray();
}

    /**
     * Update attendance record.
     *
     * @param int $attendanceId
     * @param array $data
     * @return bool
     */
    public function updateAttendance($attendanceId, $data)
    {
        return $this->update($attendanceId, $data);
    }

    /**
     * Retrieve attendance for a specific student, class section, and date.
     *
     * @param int $student_id
     * @param int $classSectionId
     * @param string $date
     * @return array|null
     */
    public function getAttendance($student_id, $classSectionId, $date)
    {
        return $this->where([
            'student_id' => $student_id,
            'class_section_id' => $classSectionId,
            'date' => $date
        ])->first();
    }

    /**
     * Retrieve reported attendance for a specific date or range.
     *
     * @param string $startDate
     * @param string|null $endDate
     * @return array
     */
    public function getReportedAttendance($startDate, $endDate = null)
    {
        $builder = $this->where(['is_reported' => 1]);

        if ($endDate) {
            $builder->where('date >=', $startDate)->where('date <=', $endDate);
        } else {
            $builder->where('date', $startDate);
        }

        return $builder->findAll();
    }

    public function getTodayAbsentees($classSectionId = null, $schoolYear = null, $semester = null)
    {
        $builder = $this->where('status', 'Absent')
            ->where('date', date('Y-m-d'));

        if ($classSectionId !== null) {
            $builder->where('class_section_id', $classSectionId);
        }

        if ($schoolYear !== null) {
            $builder->where('school_year', $schoolYear);
        }

        if ($semester !== null) {
            $builder->where('semester', $semester);
        }

        return $builder->findAll();
    }


    public function getTodayLates($classSectionId = null, $schoolYear = null, $semester = null)
    {
        $builder = $this->where('status', 'Late')
            ->where('date', date('Y-m-d'));

        if ($classSectionId !== null) {
            $builder->where('class_section_id', $classSectionId);
        }

        if ($schoolYear !== null) {
            $builder->where('school_year', $schoolYear);
        }

        if ($semester !== null) {
            $builder->where('semester', $semester);
        }

        return $builder->findAll();
    }

    public function getAbsencesByClassSection($classSectionId, $schoolYear, $semester)
    {
        return $this->where('status', 'absent')
                    ->where('class_section_id', $classSectionId)
                    ->where('school_year', $schoolYear)
                    ->where('semester', $semester)
                    ->orderBy('date', 'DESC')
                    ->findAll();
    }


    /**
     * Fetch attendance rows for a student, optionally filtered by date range.
     *
     * @param int         $studentId
     * @param string|null $startDate  'YYYY-MM-DD' inclusive
     * @param string|null $endDate    'YYYY-MM-DD' inclusive
     * @param string|null $schoolYear optional filter
     * @param string|null $semester   optional filter
     * @return array
     */
    public function getStudentAttendance(
        int $studentId,
        ?string $startDate = null,
        ?string $endDate   = null,
        ?string $schoolYear = null,
        ?string $semester   = null
    ): array {
        $qb = $this->asArray()->where('student_id', $studentId);

        if (!empty($startDate)) {
            $qb->where('date >=', $startDate);
        }
        if (!empty($endDate)) {
            $qb->where('date <=', $endDate);
        }
        if (!empty($schoolYear)) {
            $qb->where('school_year', $schoolYear);
        }
        if (!empty($semester)) {
            $qb->where('semester', $semester);
        }

        return $qb->orderBy('date', 'DESC')->findAll();
    }

    /**
     * Convenience: attendance for an exact date.
     */
    public function getStudentAttendanceOnDate(int $studentId, string $date): ?array
    {
        return $this->asArray()
            ->where(['student_id' => $studentId, 'date' => $date])
            ->first(); // returns null if none
    }

/**
 * NOT-REPORTED absences/lates for ALL students in optional date/term filters.
 * - Not reported: is_reported = 0 OR '0' OR NULL
 * - Status: ABS, ABSENT, LATE, A, L, plus prefixes like ABS_3 / LATE_2
 * - Date inclusive: >= start AND < (end + 1 day) to handle DATE/DATETIME columns
 */
public function getUnreportedAbsencesAndLates(
    ?string $schoolYear = null,
    ?string $semester   = null
): array {
    $b = $this->db->table($this->table);

    $b->select('id, student_id, class_id, class_section_id, date, status, reason, school_year, semester, is_reported')
      // Not reported: 0 / '0' / NULL (supports legacy "reported" column)
      ;
    $this->applyUnreportedFilter($b);
    // Not notified yet: exclude rows already marked notified (handles enum/string/numeric)
    $b->groupStart()
        ->where('is_notified', 0)
        ->orWhere('is_notified', '0')
        ->orWhere('is_notified', null)
        ->orWhere("LOWER(TRIM(COALESCE(is_notified, ''))) !=", 'yes')
    ->groupEnd();

    // Optional term filters (no date constraints)
    if ($schoolYear !== null && $schoolYear !== '') {
        $b->where("{$this->table}.school_year", $schoolYear);
    }
    if ($semester !== null && $semester !== '') {
        $b->where("{$this->table}.semester", $semester);
    }

    // Status filter: exact + prefixes (ABS_3, LATE_2, etc.)
    $b->groupStart()
        ->whereIn("{$this->table}.status", ['ABS','ABSENT','LATE','A','L'])
        ->orLike("{$this->table}.status", 'ABS',  'after')
        ->orLike("{$this->table}.status", 'LATE', 'after')
      ->groupEnd();

    // Sort for readability
    $b->orderBy("{$this->table}.student_id", 'ASC')
      ->orderBy("{$this->table}.date", 'DESC');

    $rows = $b->get()->getResultArray();

    // Group per student (dates included in each record)
    $out = [];
    foreach ($rows as $r) {
        $sid = (int) $r['student_id'];
        if (!isset($out[$sid])) {
            $out[$sid] = [
                'absences' => [],
                'lates'    => [],
                'counts'   => ['absences' => 0, 'lates' => 0, 'total' => 0],
            ];
        }

        $st     = strtoupper((string)($r['status'] ?? ''));
        $isAbs  = ($st === 'ABS' || $st === 'ABSENT' || $st === 'A' || str_starts_with($st, 'ABS'));
        $isLate = ($st === 'LATE' || $st === 'L' || str_starts_with($st, 'LATE'));

        $rec = [
            'id'               => $r['id'],
            'date'             => $r['date'],
            'status'           => $r['status'],
            'reason'           => $r['reason'],
            'class_id'         => $r['class_id'],
            'class_section_id' => $r['class_section_id'],
            'school_year'      => $r['school_year'],
            'semester'         => $r['semester'],
        ];

        if ($isAbs) {
            $out[$sid]['absences'][] = $rec;
            $out[$sid]['counts']['absences']++;
        } elseif ($isLate) {
            $out[$sid]['lates'][] = $rec;
            $out[$sid]['counts']['lates']++;
        }

        $out[$sid]['counts']['total'] =
            $out[$sid]['counts']['absences'] + $out[$sid]['counts']['lates'];
    }

    return $out;
}

public function markRuleAsNotifiedData(
    int $studentId,
    string $date,
    ?string $semester = null,
    ?string $schoolYear = null
): bool {
    $day    = substr($date, 0, 10);
    $start  = $day . ' 00:00:00';
    $endEx  = date('Y-m-d', strtotime($day . ' +1 day')) . ' 00:00:00';
    $builder = $this->db->table($this->table);

    $builder->where('student_id', $studentId)
        ->where('date >=', $start)
        ->where('date <', $endEx);

    if (!empty($semester)) {
        $builder->where('semester', $semester);
    }

    if (!empty($schoolYear)) {
        $builder->where('school_year', $schoolYear);
    }

    // ✅ Update ENUM field properly (compatible with legacy numeric flags)
    $builder->set('is_notified', 'yes');
    $builder->set('updated_at', utc_now());

    return $builder->update();
}

    /**
     * Mark specific attendance dates as reported + notified for a student.
     *
     * @param int   $studentId
     * @param array $dates      Array of YYYY-MM-DD strings
     */
    public function markReportedAndNotified(int $studentId, array $dates, ?string $semester = null, ?string $schoolYear = null): bool
    {
        $dates = array_values(array_unique(array_filter($dates, static function ($d) {
            return is_string($d) && preg_match('/^\d{4}-\d{2}-\d{2}$/', $d);
        })));
        if (empty($dates)) {
            return true;
        }

        $builder = $this->db->table($this->table)
            ->where('student_id', $studentId)
            ->whereIn('date', $dates)
            ->where("LOWER(TRIM(status)) IN ('absent','late')", null, false);

        if (!empty($semester)) {
            $builder->where('semester', $semester);
        }
        if (!empty($schoolYear)) {
            $builder->where('school_year', $schoolYear);
        }

        $cols = $this->reportedColumns();
        if (!empty($cols['is_reported'])) {
            $builder->set('is_reported', 'yes');
        }
        if (!empty($cols['reported'])) {
            $builder->set('reported', 1);
        }
        if ($this->db->fieldExists('is_notified', $this->table)) {
            $builder->set('is_notified', 'yes');
        }
        return (bool) $builder
            ->set('updated_at', utc_now())
            ->update();
    }

    /**
     * Fetch unreported dates for a student within N days for the given status set.
     *
     * @param int      $studentId
     * @param string[] $statuses ['absent','late']
     * @param string   $incidentDate YYYY-MM-DD reference (defaults today)
     * @param int      $lookbackDays days window backward from incidentDate (inclusive)
     */
    public function getRecentUnreportedDates(
        int $studentId,
        array $statuses,
        ?string $incidentDate = null,
        int $lookbackDays = 35,
        ?string $semester = null,
        ?string $schoolYear = null
    ): array {
        if ($studentId <= 0 || empty($statuses)) {
            return [];
        }
        $statuses = array_map('strtolower', $statuses);
        $day = $incidentDate && preg_match('/^\d{4}-\d{2}-\d{2}$/', $incidentDate)
            ? $incidentDate
            : date('Y-m-d');
        $start = date('Y-m-d', strtotime($day . ' -' . max(0, $lookbackDays) . ' days'));

        $qb = $this->db->table($this->table)
            ->select('date')
            ->where('student_id', $studentId)
            ->where('date >=', $start)
            ->where('date <=', $day)
            ->whereIn('LOWER(TRIM(status))', $statuses);
        $this->applyUnreportedFilter($qb);

        if (!empty($semester)) {
            $qb->where('semester', $semester);
        }
        if (!empty($schoolYear)) {
            $qb->where('school_year', $schoolYear);
        }

        $rows = $qb->orderBy('date', 'DESC')->get()->getResultArray();
        return array_values(array_unique(array_map(static function ($r) {
            return substr((string)($r['date'] ?? ''), 0, 10);
        }, $rows)));
    }

    private function reportedColumns(): array
    {
        if ($this->reportedColumns !== null) {
            return $this->reportedColumns;
        }
        $this->reportedColumns = [
            'is_reported' => $this->db->fieldExists('is_reported', $this->table),
            'reported'    => $this->db->fieldExists('reported', $this->table),
        ];
        return $this->reportedColumns;
    }

    private function applyUnreportedFilter($qb): void
    {
        $cols = $this->reportedColumns();
        if (!empty($cols['is_reported'])) {
            $qb->groupStart()
                ->where('is_reported', 'no')
                ->orWhere('is_reported', 0)
                ->orWhere('is_reported', '0')
                ->orWhere('is_reported', null)
            ->groupEnd();
        }
        if (!empty($cols['reported'])) {
            $qb->where("(LOWER(TRIM(COALESCE(reported, ''))) NOT IN ('yes','1','true','y','on'))", null, false);
        }
    }


}
