<?php

namespace App\Modules\Attendance\Controllers;

use App\Core\BaseApiController;
use App\Modules\Auth\Entities\Role;
use App\Modules\Auth\Services\AuthService;
use App\Modules\Attendance\Services\AttendanceReportService;
use CodeIgniter\HTTP\ResponseInterface;

/**
 * Attendance Report Controller
 *
 * On-the-fly schedule attendance reports (expected, present, late, absent).
 */
class AttendanceReportController extends BaseApiController
{
    protected AttendanceReportService $reportService;
    protected AuthService $authService;

    public function __construct()
    {
        $this->reportService = new AttendanceReportService();
        $this->authService   = new AuthService();
    }

    /**
     * GET /api/attendance/reports
     *
     * Query:
     * - from_date (YYYY-MM-DD, optional, default: today if both empty)
     * - to_date   (YYYY-MM-DD, optional, default: today if both empty)
     * - class_id  (int, optional)
     * - student_id (int, optional)
     * - status    (PRESENT,LATE,OUTSIDE_ZONE,NO_SCHEDULE,INVALID_DEVICE; optional)
     *
     * Returns recap per hari/per kelas + daftar detail kehadiran.
     */
    public function index(): ResponseInterface
    {
        $user = $this->authService->currentUser();
        if (! $user) {
            return $this->errorResponse('Unauthorized', null, null, ResponseInterface::HTTP_UNAUTHORIZED);
        }

        $roles     = $user['roles'] ?? [];
        $roleCodes = array_column($roles, 'role_code');

        $isAdmin   = in_array(Role::CODE_ADMIN, $roleCodes, true);
        $isGuruBk  = in_array(Role::CODE_GURU_BK, $roleCodes, true);
        $isWali    = in_array(Role::CODE_WALI_KELAS, $roleCodes, true);
        $isGuruMap = in_array(Role::CODE_GURU_MAPEL, $roleCodes, true);

        // ORANG_TUA pakai Portal Orang Tua, bukan endpoint ini
        if (! $isAdmin && ! $isGuruBk && ! $isWali && ! $isGuruMap) {
            return $this->errorResponse('Forbidden', null, null, ResponseInterface::HTTP_FORBIDDEN);
        }

        $from = $this->request->getGet('from_date');
        $to   = $this->request->getGet('to_date');

        $today = date('Y-m-d');
        if (($from === null || $from === '') && ($to === null || $to === '')) {
            $from = $today;
            $to   = $today;
        }

        if ($from !== null && $from !== '' && ! preg_match('/^\d{4}-\d{2}-\d{2}$/', $from)) {
            return $this->errorResponse('from_date must be YYYY-MM-DD', null, null, ResponseInterface::HTTP_BAD_REQUEST);
        }
        if ($to !== null && $to !== '' && ! preg_match('/^\d{4}-\d{2}-\d{2}$/', $to)) {
            return $this->errorResponse('to_date must be YYYY-MM-DD', null, null, ResponseInterface::HTTP_BAD_REQUEST);
        }

        $classId   = (int) $this->request->getGet('class_id');
        $studentId = (int) $this->request->getGet('student_id');
        $status    = $this->request->getGet('status');

        if ($status !== null && $status !== '') {
            $allowedStatus = ['PRESENT', 'LATE', 'OUTSIDE_ZONE', 'NO_SCHEDULE', 'INVALID_DEVICE'];
            if (! in_array($status, $allowedStatus, true)) {
                return $this->errorResponse('Invalid status value', null, null, ResponseInterface::HTTP_BAD_REQUEST);
            }
        }

        $db = \Config\Database::connect();
        $builder = $db->table('attendance_sessions AS att')
            ->select(
                'att.id, att.attendance_date, att.status, att.checkin_at, ' .
                's.id AS student_id, s.nisn, s.name AS student_name, ' .
                'c.id AS class_id, c.grade, c.major, c.name AS class_name, ' .
                'sch.id AS schedule_id, sub.id AS subject_id, sub.name AS subject_name, ' .
                'u.id AS teacher_user_id, u.name AS teacher_name'
            )
            ->join('students AS s', 's.id = att.student_id', 'inner')
            ->join('classes AS c', 'c.id = s.class_id', 'left')
            ->join('schedules AS sch', 'sch.id = att.schedule_id', 'left')
            ->join('subjects AS sub', 'sub.id = sch.subject_id', 'left')
            ->join('users AS u', 'u.id = sch.teacher_user_id', 'left');

        if ($from) {
            $builder->where('att.attendance_date >=', $from);
        }
        if ($to) {
            $builder->where('att.attendance_date <=', $to);
        }
        if ($classId > 0) {
            $builder->where('c.id', $classId);
        }
        if ($studentId > 0) {
            $builder->where('s.id', $studentId);
        }
        if ($status) {
            $builder->where('att.status', $status);
        }

        // RBAC batasan data
        if ($isWali) {
            $builder->where('c.wali_user_id', (int) $user['id']);
        } elseif ($isGuruMap) {
            $builder->where('sch.teacher_user_id', (int) $user['id']);
        } elseif (! $isAdmin && ! $isGuruBk) {
            // Should not reach here, tetapi jaga-jaga
            return $this->errorResponse('Forbidden', null, null, ResponseInterface::HTTP_FORBIDDEN);
        }

        $builder->orderBy('att.attendance_date', 'DESC')
            ->orderBy('c.grade', 'ASC')
            ->orderBy('c.major', 'ASC')
            ->orderBy('c.name', 'ASC')
            ->orderBy('s.name', 'ASC');

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

        // Detail records
        $records = array_map(static function (array $r): array {
            $classLabel = null;
            if ($r['grade'] !== null || $r['major'] !== null || $r['class_name'] !== null) {
                $parts = array_filter([
                    trim((string) ($r['grade'] ?? '')),
                    trim((string) ($r['major'] ?? '')),
                    trim((string) ($r['class_name'] ?? '')),
                ]);
                $classLabel = implode(' ', $parts);
            }

            return [
                'id'              => (int) $r['id'],
                'attendance_date' => $r['attendance_date'],
                'status'          => $r['status'],
                'checkin_at'      => $r['checkin_at'],
                'student_id'      => (int) $r['student_id'],
                'student_name'    => $r['student_name'],
                'nisn'            => $r['nisn'],
                'class_id'        => $r['class_id'] !== null ? (int) $r['class_id'] : null,
                'class_label'     => $classLabel,
                'schedule_id'     => $r['schedule_id'] !== null ? (int) $r['schedule_id'] : null,
                'subject_id'      => $r['subject_id'] !== null ? (int) $r['subject_id'] : null,
                'subject_name'    => $r['subject_name'],
                'teacher_user_id' => $r['teacher_user_id'] !== null ? (int) $r['teacher_user_id'] : null,
                'teacher_name'    => $r['teacher_name'],
            ];
        }, $rows);

        // Rekap per hari & kelas
        $summaryMap = [];
        foreach ($records as $rec) {
            $date  = $rec['attendance_date'];
            $cid   = $rec['class_id'] ?? 0;
            $label = $rec['class_label'] ?? '-';
            $key   = $date . '|' . $cid;

            if (! isset($summaryMap[$key])) {
                $summaryMap[$key] = [
                    'attendance_date' => $date,
                    'class_id'        => $cid,
                    'class_label'     => $label,
                    'total'           => 0,
                    'present'         => 0,
                    'late'            => 0,
                    'outside_zone'    => 0,
                    'no_schedule'     => 0,
                    'invalid_device'  => 0,
                ];
            }

            $summaryMap[$key]['total']++;
            switch ($rec['status']) {
                case 'PRESENT':
                    $summaryMap[$key]['present']++;
                    break;
                case 'LATE':
                    $summaryMap[$key]['late']++;
                    break;
                case 'OUTSIDE_ZONE':
                    $summaryMap[$key]['outside_zone']++;
                    break;
                case 'NO_SCHEDULE':
                    $summaryMap[$key]['no_schedule']++;
                    break;
                case 'INVALID_DEVICE':
                    $summaryMap[$key]['invalid_device']++;
                    break;
            }
        }

        $summary = array_values($summaryMap);

        usort($summary, static function (array $a, array $b): int {
            if ($a['attendance_date'] === $b['attendance_date']) {
                return strcmp((string) $a['class_label'], (string) $b['class_label']);
            }
            return strcmp($a['attendance_date'], $b['attendance_date']);
        });

        $payload = [
            'filters' => [
                'from_date'  => $from,
                'to_date'    => $to,
                'class_id'   => $classId > 0 ? $classId : null,
                'student_id' => $studentId > 0 ? $studentId : null,
                'status'     => $status ?: null,
            ],
            'summary' => $summary,
            'records' => $records,
        ];

        return $this->successResponse($payload, 'Attendance reports');
    }

    /**
     * GET /api/attendance/report/schedule/{scheduleId}?date=YYYY-MM-DD
     *
     * @param int|string $scheduleId From route (:num)
     * @return ResponseInterface
     */
    public function scheduleReport($scheduleId): ResponseInterface
    {
        $scheduleId = (int) $scheduleId;
        $date       = $this->request->getGet('date');

        if ($date === null || $date === '') {
            return $this->errorResponse('Query parameter date (YYYY-MM-DD) is required', null, null, 400);
        }

        $date = (string) $date;
        if (!preg_match('/^\d{4}-\d{2}-\d{2}$/', $date)) {
            return $this->errorResponse('Parameter date must be YYYY-MM-DD', null, null, 400);
        }

        $userContext = $this->authService->currentUser();
        $report      = $this->reportService->getScheduleAttendanceReport($scheduleId, $date, $userContext);

        if ($report === null) {
            return $this->errorResponse('Schedule not found or access denied', null, null, 404);
        }

        return $this->successResponse($report, 'Schedule attendance report');
    }
}
