<?php

namespace App\Services\Grading;

use App\Models\Configuration;
use Illuminate\Support\Facades\DB;

class HomeworkTrackingService
{
    private array $teacherAssignmentCache = [];

    public function __construct(private HomeworkTrackingCalendarService $calendarService)
    {
    }

    public function report(?string $semester = null, ?string $schoolYear = null, int $page = 1): array
    {
        $semester = $semester ?: (string) (Configuration::getConfig('semester') ?? '');
        $schoolYear = $schoolYear ?: (string) (Configuration::getConfig('school_year') ?? '');

        [$start, $end] = $this->calendarService->buildDateRange($schoolYear, $semester);
        $sundays = $this->calendarService->buildSundays($start, $end);
        $eventDays = $this->calendarService->eventDays($schoolYear);
        $dateToIndex = $this->calendarService->dateToIndex($sundays, $eventDays);

        $limitToSemester = $this->hasTeacherAssignments($schoolYear);

        $homeworkByIndex = $this->loadHomeworkByIndex($schoolYear, $semester, $limitToSemester);
        $homeworkByDate = $this->loadHomeworkByDate($schoolYear, $semester, $limitToSemester, $sundays, $eventDays);
        $teachers = $this->loadTeachers($schoolYear);

        $perPage = 8;
        $totalRows = count($teachers);
        $totalPages = max(1, (int) ceil($totalRows / $perPage));
        $page = max(1, min($page, $totalPages));
        $offset = ($page - 1) * $perPage;
        $teachersPage = array_slice($teachers, $offset, $perPage);

        return [
            'semester' => $semester,
            'school_year' => $schoolYear,
            'sundays' => $sundays,
            'event_days' => $eventDays,
            'date_to_index' => $dateToIndex,
            'teachers' => $teachersPage,
            'has_homework' => $homeworkByIndex['has_homework'],
            'hw_entered_at' => $homeworkByIndex['entered_at'],
            'has_homework_by_date' => $homeworkByDate['has_homework'],
            'hw_entered_at_by_date' => $homeworkByDate['entered_at'],
            'page' => $page,
            'total_pages' => $totalPages,
            'per_page' => $perPage,
            'total_rows' => $totalRows,
        ];
    }

    private function hasTeacherAssignments(string $schoolYear): bool
    {
        $year = trim((string) $schoolYear);
        if ($year === '') {
            return false;
        }

        if (array_key_exists($year, $this->teacherAssignmentCache)) {
            return $this->teacherAssignmentCache[$year];
        }

        $cnt = DB::table('teacher_class')->where('school_year', $year)->count();
        $this->teacherAssignmentCache[$year] = $cnt > 0;

        return $this->teacherAssignmentCache[$year];
    }

    private function loadHomeworkByIndex(string $schoolYear, string $semester, bool $limitToSemester): array
    {
        $query = DB::table('homework')
            ->select('class_section_id', 'homework_index', DB::raw('MIN(created_at) as first_created'), DB::raw('COUNT(*) as cnt'))
            ->where('school_year', $schoolYear);

        if ($limitToSemester && $semester !== '') {
            $query->where('semester', $semester);
        }

        $rows = $query->groupBy('class_section_id', 'homework_index')->get();

        $hasHomework = [];
        $enteredAt = [];
        foreach ($rows as $row) {
            $csid = (int) $row->class_section_id;
            $hi = (int) $row->homework_index;
            $cnt = (int) $row->cnt;
            if ($csid > 0 && $hi > 0 && $cnt > 0) {
                $hasHomework[$csid][$hi] = true;
                $dateStr = substr((string) ($row->first_created ?? ''), 0, 10);
                $enteredAt[$csid][$hi] = $dateStr ?: null;
            }
        }

        return ['has_homework' => $hasHomework, 'entered_at' => $enteredAt];
    }

    private function loadHomeworkByDate(string $schoolYear, string $semester, bool $limitToSemester, array $sundays, array $eventDays): array
    {
        $query = DB::table('homework')
            ->select(DB::raw('class_section_id, DATE(created_at) as hw_date, MIN(created_at) as first_created, COUNT(*) as cnt'))
            ->where('school_year', $schoolYear);

        if ($limitToSemester && $semester !== '') {
            $query->where('semester', $semester);
        }

        $rows = $query
            ->groupBy('class_section_id', DB::raw('DATE(created_at)'))
            ->orderBy('hw_date', 'ASC')
            ->get();

        $hasHomework = [];
        $enteredAt = [];

        foreach ($rows as $row) {
            $csid = (int) $row->class_section_id;
            $date = substr((string) ($row->hw_date ?? ''), 0, 10);
            $cnt = (int) $row->cnt;
            $firstCreated = substr((string) ($row->first_created ?? ''), 0, 10);
            if ($csid <= 0 || !$date || $cnt <= 0) {
                continue;
            }

            $baseIndex = -1;
            for ($i = count($sundays) - 1; $i >= 0; $i--) {
                if ($sundays[$i] <= $date) {
                    $baseIndex = $i;
                    break;
                }
            }
            if ($baseIndex < 0) {
                continue;
            }

            $j = $baseIndex;
            while ($j >= 0 && !empty($eventDays[$sundays[$j]])) {
                $j--;
            }
            if ($j < 0) {
                continue;
            }
            $sunday = $sundays[$j];

            $hasHomework[$csid][$sunday] = true;
            $candidate = $firstCreated ?: $date;
            if (empty($enteredAt[$csid][$sunday]) || ($candidate && $candidate < $enteredAt[$csid][$sunday])) {
                $enteredAt[$csid][$sunday] = $candidate;
            }
        }

        return ['has_homework' => $hasHomework, 'entered_at' => $enteredAt];
    }

    private function loadTeachers(string $schoolYear): array
    {
        $rows = DB::table('teacher_class as tc')
            ->select('tc.class_section_id', 'tc.position', 'cs.class_section_name', 'cs.class_id', 'u.firstname', 'u.lastname')
            ->leftJoin('classSection as cs', 'cs.class_section_id', '=', 'tc.class_section_id')
            ->leftJoin('users as u', 'u.id', '=', 'tc.teacher_id')
            ->where('tc.school_year', $schoolYear)
            ->whereNotNull('tc.class_section_id')
            ->whereIn('tc.position', ['main', 'ta'])
            ->orderBy('cs.class_id', 'ASC')
            ->orderBy('cs.class_section_name', 'ASC')
            ->orderByRaw("CASE tc.position WHEN 'main' THEN 0 WHEN 'ta' THEN 1 ELSE 2 END")
            ->orderBy('u.firstname', 'ASC')
            ->get();

        $bySection = [];
        foreach ($rows as $row) {
            $sid = (int) $row->class_section_id;
            if ($sid <= 0) {
                continue;
            }
            if (!isset($bySection[$sid])) {
                $bySection[$sid] = [
                    'class_section_id' => $sid,
                    'class_id' => (int) ($row->class_id ?? 0),
                    'class_section_name' => (string) ($row->class_section_name ?? ''),
                    'teachers' => [],
                    'tas' => [],
                ];
            }
            $name = trim((string) ($row->firstname ?? '') . ' ' . (string) ($row->lastname ?? ''));
            $pos = strtolower((string) ($row->position ?? ''));
            if ($name !== '') {
                if ($pos === 'main') {
                    $bySection[$sid]['teachers'][] = $name;
                } elseif ($pos === 'ta') {
                    $bySection[$sid]['tas'][] = $name;
                }
            }
        }

        $teachers = array_values($bySection);
        usort($teachers, function ($a, $b) {
            $ai = (int) ($a['class_id'] ?? 0);
            $bi = (int) ($b['class_id'] ?? 0);
            $order = function (int $cid): int {
                if ($cid === 13) return 0;
                if ($cid >= 1 && $cid <= 11) return $cid;
                if ($cid === 12) return 99;
                return 200 + $cid;
            };
            $cmp = $order($ai) <=> $order($bi);
            if ($cmp !== 0) {
                return $cmp;
            }
            return strnatcasecmp($a['class_section_name'] ?? '', $b['class_section_name'] ?? '');
        });

        return $teachers;
    }
}
