<?php

namespace App\Services\AttendanceTracking;

use App\Models\AttendanceData;
use Carbon\Carbon;
use Illuminate\Support\Facades\DB;
use Throwable;

class AttendancePendingViolationService
{
    public function __construct(
        protected AttendanceData $attendanceDataModel,
        protected ViolationRuleEngineService $violationRuleEngine,
        protected AttendanceViolationStudentResolverService $studentResolverService
    ) {
    }

    public function getPendingViolations(
        string $defaultSchoolYear,
        ?string $schoolYearParam = null,
        ?string $semesterParam = null
    ): array {
        $schoolYear = filled($schoolYearParam) ? (string) $schoolYearParam : (string) $defaultSchoolYear;
        $semester   = filled($semesterParam) ? (string) $semesterParam : null;

        $debugInfo = [
            'school_year_param' => $schoolYear,
            'semester_param'    => $semester,
            'class_students'    => 0,
            'student_ids'       => 0,
            'attendance_rows'   => 0,
            'filtered_rows'     => 0,
            'violations'        => 0,
            'active_weeks'      => 0,
            'abs_last5'         => 0,
            'late_last5'        => 0,
        ];

        $resolved = $this->studentResolverService->resolveForSchoolYear($schoolYear, $semester);

        $schoolYear      = (string) ($resolved['school_year'] ?? $schoolYear);
        $semester        = $resolved['semester'] ?? $semester;
        $studentIds      = $resolved['student_ids'] ?? [];
        $studentCodes    = $resolved['student_codes'] ?? [];
        $students        = $resolved['students'] ?? [];
        $studentCodeToId = $resolved['student_code_to_id'] ?? [];
        $existingIds     = $resolved['existing_ids'] ?? [];
        $resolverDebug   = $resolved['debug'] ?? [];

        $debugInfo['class_students'] = $resolverDebug['class_students'] ?? 0;
        $debugInfo['student_ids']    = $resolverDebug['student_ids'] ?? 0;

        if (empty($studentIds) && empty($studentCodes)) {
            return [
                'students'    => [],
                'school_year' => $schoolYear,
                'semester'    => $semester,
                'error'       => 'No student identifiers found for the current school year.',
                'debug'       => $debugInfo,
            ];
        }

        if (empty($students)) {
            return [
                'students'    => [],
                'school_year' => $schoolYear,
                'semester'    => $semester,
                'error'       => 'No students found matching attendance records.',
                'debug'       => $debugInfo,
            ];
        }

        $today = Carbon::today();
        [$syStart, $syEnd] = $this->violationRuleEngine->deriveSchoolYearBounds($schoolYear);
        $start = Carbon::parse($syStart)->startOfDay();
        $rangeEnd = Carbon::parse(min($syEnd, $today->format('Y-m-d')))->startOfDay();
        $endEx = $rangeEnd->copy()->addDay();

        $qb = $this->attendanceDataModel->query()
            ->select([
                'id',
                'student_id',
                'class_id',
                'class_section_id',
                'date',
                'status',
                'reason',
                'school_year',
                'semester',
                'is_reported',
                'is_notified',
            ])
            ->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
            ->when(!empty($semester), fn ($q) => $q->where('semester', $semester))
            ->where(function ($q) use ($studentIds, $studentCodes) {
                if (!empty($studentIds)) {
                    $q->whereIn('student_id', $studentIds);
                }
                if (!empty($studentCodes)) {
                    if (!empty($studentIds)) {
                        $q->orWhereIn('student_id', $studentCodes);
                    } else {
                        $q->whereIn('student_id', $studentCodes);
                    }
                }
            });

        $this->violationRuleEngine->applyUnreportedAttendanceFilter($qb, $this->attendanceDataModel->getTable());

        $qb->whereRaw("(LOWER(TRIM(COALESCE(is_notified, ''))) NOT IN ('yes','1'))")
            ->whereRaw("LOWER(TRIM(status)) IN ('absent','late')")
            ->where('date', '>=', $start->format('Y-m-d'))
            ->where('date', '<', $endEx->format('Y-m-d'));

        $termRows = $qb->orderByDesc('date')->get()->toArray();

        if (empty($termRows)) {
            $latestAttendanceTerm = DB::table($this->attendanceDataModel->getTable())
                ->select('school_year', 'semester', 'date')
                ->when(!empty($studentIds), fn ($q) => $q->whereIn('student_id', $studentIds))
                ->orderByDesc('date')
                ->first();

            if ($latestAttendanceTerm) {
                $schoolYear = !empty($latestAttendanceTerm->school_year)
                    ? (string) $latestAttendanceTerm->school_year
                    : $schoolYear;

                $semester = !empty($latestAttendanceTerm->semester)
                    ? (string) $latestAttendanceTerm->semester
                    : $semester;

                [$syStart, $syEnd] = $this->violationRuleEngine->deriveSchoolYearBounds($schoolYear ?: $defaultSchoolYear);
                $start = Carbon::parse($syStart)->startOfDay();
                $rangeEnd = Carbon::parse(min($syEnd, $today->format('Y-m-d')))->startOfDay();
                $endEx = $rangeEnd->copy()->addDay();

                $qb = $this->attendanceDataModel->query()
                    ->select([
                        'id',
                        'student_id',
                        'class_id',
                        'class_section_id',
                        'date',
                        'status',
                        'reason',
                        'school_year',
                        'semester',
                        'is_reported',
                        'is_notified',
                    ])
                    ->when(!empty($schoolYear), fn ($q) => $q->where('school_year', $schoolYear))
                    ->when(!empty($semester), fn ($q) => $q->where('semester', $semester))
                    ->where(function ($q) use ($studentIds, $studentCodes) {
                        if (!empty($studentIds)) {
                            $q->whereIn('student_id', $studentIds);
                        }
                        if (!empty($studentCodes)) {
                            if (!empty($studentIds)) {
                                $q->orWhereIn('student_id', $studentCodes);
                            } else {
                                $q->whereIn('student_id', $studentCodes);
                            }
                        }
                    });

                $this->violationRuleEngine->applyUnreportedAttendanceFilter($qb, $this->attendanceDataModel->getTable());

                $qb->whereRaw("(LOWER(TRIM(COALESCE(is_notified, ''))) NOT IN ('yes','1'))")
                    ->whereRaw("LOWER(TRIM(status)) IN ('absent','late')")
                    ->where('date', '>=', $start->format('Y-m-d'))
                    ->where('date', '<', $endEx->format('Y-m-d'));

                $termRows = $qb->orderByDesc('date')->get()->toArray();
            }

            if (empty($termRows)) {
                return [
                    'students'    => [],
                    'school_year' => $schoolYear,
                    'semester'    => $semester,
                    'debug'       => $debugInfo,
                ];
            }
        }

        $attendanceRows = [];
        foreach ($termRows as $row) {
            $dStr = $row['date'] ?? null;
            if (!$dStr) {
                continue;
            }

            try {
                $d = Carbon::parse($dStr);
            } catch (Throwable) {
                continue;
            }

            if ($d->lt($start) || !$d->lt($endEx)) {
                continue;
            }

            $sid = $this->studentResolverService->ensureAttendanceStudentExists(
                $students,
                $studentCodeToId,
                $existingIds,
                $row['student_id'] ?? null
            );

            if ($sid === null || $sid <= 0) {
                continue;
            }

            $row['student_id'] = $sid;
            $row['status'] = strtolower(trim((string) ($row['status'] ?? '')));
            $row['date'] = $d->format('Y-m-d');

            $attendanceRows[] = $row;
        }

        if (empty($attendanceRows)) {
            return [
                'students'    => [],
                'school_year' => $schoolYear,
                'semester'    => $semester,
                'debug'       => $debugInfo,
            ];
        }

        $debugInfo['attendance_rows'] = count($termRows);
        $debugInfo['filtered_rows']   = count($attendanceRows);

        $violations = $this->violationRuleEngine->computeViolations(
            $students,
            $attendanceRows,
            $schoolYear,
            null,
            $attendanceRows
        );

        $ruleDebug = $this->violationRuleEngine->getDebugCompute();
        $debugInfo['violations']   = count($violations);
        $debugInfo['active_weeks'] = $ruleDebug['active_weeks'] ?? 0;
        $debugInfo['by_student']   = $ruleDebug['by_student'] ?? 0;
        $debugInfo['abs_last5']    = $ruleDebug['abs_last5'] ?? 0;
        $debugInfo['late_last5']   = $ruleDebug['late_last5'] ?? 0;

        return [
            'students'    => $violations,
            'school_year' => $schoolYear,
            'semester'    => $semester,
            'debug'       => $debugInfo,
        ];
    }
}