<?php

namespace App\Controllers\View;

use App\Models\HomeworkModel;
use App\Models\StudentModel;
use App\Models\StudentClassModel;
use App\Controllers\BaseController;
use App\Models\TeacherClassModel;
use App\Models\ConfigurationModel;
use App\Models\UserModel;
use RuntimeException;
use App\Services\SemesterScoreService;
use Config\Services;
use App\Controllers\View\GradingController;
use App\Models\GradingLockModel;
use App\Models\MissingScoreOverrideModel;

class HomeworkController extends BaseController
{
    protected $db;
    protected $semesterScoreService;
    protected $configModel;
    protected $homeworkModel;
    protected $userModel;
    protected $schoolYear;
    protected $semester;
    protected $studentClassModel;
    protected $studentModel;
    protected $teacherClassModel;
    protected $gradingLockModel;
    protected $missingScoreOverrideModel;

    public function __construct()
    {
        $this->db = \Config\Database::connect();
        $this->teacherClassModel = new TeacherClassModel();
        $this->homeworkModel = new HomeworkModel();
        $this->userModel = new UserModel();
        $this->studentClassModel = new StudentClassModel();
        $this->studentModel      = new StudentModel();
        $this->configModel = new ConfigurationModel();

        $this->schoolYear = $this->configModel->getConfig('school_year');
        $this->semester = $this->configModel->getConfig('semester');

        // Log the service initialization
        log_message('debug', 'Initializing SemesterScoreService');

        //$this->semesterScoreService = Services::SemesterScoreService();
        $this->semesterScoreService = service('semesterScoreService');
        // $this->semesterScoreService = \Config\Services::semesterScoreService();   
        $this->gradingLockModel = new GradingLockModel();
        $this->missingScoreOverrideModel = new MissingScoreOverrideModel();

        // Check if the service is null
        if ($this->semesterScoreService === null) {
            log_message('error', 'SemesterScoreService is null');
        }
    }

    public function updateHomeworkScores(?array $scores = null, ?int $updatedBy = null, ?int $classSectionId = null)
    {
        $scores = $this->request->getPost('scores');
        $semester = $this->request->getPost('semester') ?? $this->semester;
        $schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
        $this->assertSchoolYearWritable($this->resolveSchoolYearContext());

        if ($updatedBy === null) {
            $updatedBy = session()->get('user_id');
        }
        $classSectionId = $this->request->getPost('class_section_id') ?? session()->get('class_section_id');
        $classSectionId = (int) ($classSectionId ?? 0);
        if ($classSectionId > 0 && $this->isScoresLocked($classSectionId, $semester, $schoolYear)) {
            return redirect()->back()->with('error', 'Scores are locked for this class. Unlock to edit.');
        }

        $missingOk = $this->request->getPost('missing_ok') ?? [];
        $studentIds = is_array($scores) ? array_keys($scores) : array_keys((array) $missingOk);
        $indexSet = [];
        if (is_array($scores)) {
            foreach ($scores as $studentId => $hwData) {
                if (!is_array($hwData)) {
                    continue;
                }
                foreach ($hwData as $index => $score) {
                    if (is_numeric($index)) {
                        $indexSet[(int)$index] = true;
                    }
                }
            }
        }
        $checkedItems = [];
        if (is_array($missingOk)) {
            foreach ($missingOk as $studentId => $indexes) {
                if (!is_array($indexes)) {
                    continue;
                }
                foreach ($indexes as $index => $flag) {
                    if (!is_numeric($index)) {
                        continue;
                    }
                    $checkedItems[] = [
                        'student_id' => (int) $studentId,
                        'item_index' => (int) $index,
                    ];
                }
            }
        }
        $this->missingScoreOverrideModel->replaceOverrides(
            $classSectionId,
            (string) $semester,
            (string) $schoolYear,
            'homework',
            $studentIds,
            array_keys($indexSet),
            $checkedItems,
            $updatedBy
        );

        if (is_array($scores)) {
            foreach ($scores as $studentId => $hwData) {
                if (!is_numeric($studentId)) continue;

                $student = $this->studentModel->find($studentId);
                if (!$student) continue;

                foreach ($hwData as $index => $score) {
                    $rawScore = $score ?? null;
                    $isBlank = $rawScore === null || (is_string($rawScore) && trim($rawScore) === '');
                    $normalizedScore = (!$isBlank && is_numeric($rawScore)) ? (float) $rawScore : null;

                    // STEP 1: Always fetch the existing record
                    $existing = $this->homeworkModel->where([
                        'student_id'       => $studentId,
                        'homework_index'   => $index,
                        'class_section_id' => $classSectionId,
                        //'teacher_id'       => $updatedBy,
                        'semester'         => $semester,
                        'school_year'      => $schoolYear,
                    ])->first();

                    // STEP 2: Save numeric score (blank -> null)
                    $data = [
                        'student_id'       => $studentId,
                        'school_id'        => $student['school_id'] ?? '',
                        'class_section_id' => $classSectionId,
                        'updated_by'       => $updatedBy,
                        'homework_index'   => $index,
                        'score'            => $normalizedScore,
                        'semester'         => $semester,
                        'school_year'      => $schoolYear,
                        'updated_at'       => utc_now(),
                    ];

                    if ($isBlank) {
                        if ($existing) {
                            $this->homeworkModel->update($existing['id'], $data);
                            log_message('debug', "Updated homework ID {$existing['id']} with score null");
                        } else {
                            $data['created_at'] = utc_now();
                            $this->homeworkModel->insert($data);
                            log_message('debug', "Inserted blank homework for student $studentId index $index");
                        }
                        continue;
                    }

                    if ($existing) {
                        $this->homeworkModel->update($existing['id'], $data);
                        log_message('debug', "Updated homework ID {$existing['id']} with score {$normalizedScore}");
                    } else {
                        $data['created_at'] = utc_now();
                        $this->homeworkModel->insert($data);
                        log_message('debug', "Inserted score for student $studentId index $index");
                    }
                }
            }
        }
        $studentUserInfo = $this->studentModel->getStudentInfoByClassSectionId($classSectionId, $semester, $schoolYear);

        // Call the updateScoresForStudents method
        try {
            $this->semesterScoreService->updateScoresForStudents($studentUserInfo, $semester, $schoolYear);
        } catch (RuntimeException $e) {
            // Handle error
        }

        return redirect()->to(base_url('/teacher/addHomework'))->with('status', 'Homework scores updated successfully.');
    }


    public function addNextHomeworkColumn()
    {
        $updatedBy = session()->get('user_id');
        $classSectionId = session()->get('class_section_id');
        $selectedSemester = $this->getSelectedSemester();
        $normalized = $this->normalizeSemesterSelection($selectedSemester);
        $semesterLabel = $normalized !== '' ? ucfirst($normalized) : $selectedSemester;
        $schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
        $this->assertSchoolYearWritable($this->resolveSchoolYearContext());

        // Step 1: Get the highest existing homework_index
        $existingIndexes = $this->homeworkModel
            ->select('homework_index')
            ->where('class_section_id', $classSectionId)
            //->where('teacher_id', $updatedBy)
            ->whereIn('semester', $this->getSemesterVariants($semesterLabel))
            ->where('school_year', $schoolYear)
            ->groupBy('homework_index')
            ->orderBy('homework_index', 'DESC')
            ->findAll();

        $maxIndex = 0;
        foreach ($existingIndexes as $row) {
            if (isset($row['homework_index']) && is_numeric($row['homework_index'])) {
                $maxIndex = max($maxIndex, (int)$row['homework_index']);
            }
        }

        $nextIndex = $maxIndex + 1;

        // Step 2: Get all students in the class
        $students = $this->studentClassModel
            ->where('class_section_id', $classSectionId)
            ->where('school_year', $schoolYear)
            ->findAll();

        // Step 3: Insert a new homework row for each student if not already exists
        $firstInsertedId = null;
        foreach ($students as $i => $student) {
            $studentId = $student['student_id'];

            // Check if record already exists
            $existing = $this->homeworkModel
                ->where('student_id', $studentId)
                ->where('homework_index', $nextIndex)
                ->where('class_section_id', $classSectionId)
                //->where('teacher_id', $updatedBy)
                ->whereIn('semester', $this->getSemesterVariants($semesterLabel))
                ->where('school_year', $schoolYear)
                ->first();

            if ($existing) continue;

            $insertData = [
                'student_id'       => $studentId,
                'school_id'        => '', // Optional: populate if needed
                'class_section_id' => $classSectionId,
                'updated_by'       => $updatedBy,
                'homework_index'   => $nextIndex,
                'score'            => null,
                'semester'         => $semesterLabel,
                'school_year'      => $schoolYear,
                'created_at'       => utc_now(),
                'updated_at'       => utc_now()
            ];

            $id = $this->homeworkModel->insert($insertData, true);
            if ($i === 0) {
                $firstInsertedId = $id;
            }
        }

        // Step 4: Return index and ID to frontend
        return $this->response->setJSON([
            'status' => 'success',
            'homework_index' => $nextIndex,
            'new_homework_id' => $firstInsertedId
        ]);
    }


    public function showHomework()
    {
        $updatedBy = session()->get('user_id');
        $semester = $this->getSelectedSemester();
        $schoolYear = $this->currentSchoolYearName((string) ($this->schoolYear ?? ''));
        $classSectionId = (int) (
            $this->request->getGet('class_section_id')
            ?? $this->request->getPost('class_section_id')
            ?? 0
        );
        if ($classSectionId <= 0) {
            $classSectionId = (int) ($this->getClassSectionIdForTeacher($updatedBy, $schoolYear, $semester) ?? 0);
        }
        if (!$classSectionId) {
            return redirect()->back()->with('status', 'No class section found for the current teacher.');
        }

        session()->set('class_section_id', $classSectionId);

        $homeworkHeaders = $this->getHomeworkHeaders($classSectionId, $semester, $schoolYear);
        if (empty($homeworkHeaders)) {
            $homeworkHeaders = [1];
        }
        $students = $this->getStudentsWithHomeworkScores(
            $classSectionId,
            $homeworkHeaders,
            $semester,
            $schoolYear
        );
        $missingOkMap = $this->missingScoreOverrideModel->getOverridesMap($classSectionId, $semester, $schoolYear, 'homework');

        return view('teacher/add_homework', [
            'students'         => $students,
            'homeworkHeaders'  => $homeworkHeaders,
            'semester'         => $semester,
            'schoolYear'       => $schoolYear,
            'class_section_id' => $classSectionId,
            'missingOkMap'     => $missingOkMap,
        ]);
    }

    // In your GradingController (or the controller that owns this action)
    public function showHomeworkMngt()
    {
        // Accept POST first, then GET (query string), then session fallback
        $incomingId = $this->request->getPost('class_section_id');
        if (!$incomingId) {
            $incomingId = $this->request->getGet('class_section_id');
        }

        $classSectionId = (int) ($incomingId ?: (session()->get('class_section_id') ?? 0));

        if ($classSectionId <= 0) {
            return redirect()->back()->with('status', 'No class section found for the current teacher or selection.');
        }
        $updatedBy = (int) (session()->get('user_id') ?? 0);

        $semesterParam = $this->request->getPost('semester')
            ?? $this->request->getGet('semester')
            ?? $this->request->getGet('filter');
        $normalizedSemester = $this->normalizeSemesterSelection($semesterParam);
        if ($normalizedSemester !== '') {
            $label = ucfirst($normalizedSemester);
            $session = session();
            $session->set('teacher_scores_selected_semester', $label);
            $session->set('semester', $label);
        }

        $schoolYearParam = $this->request->getPost('school_year') ?? $this->request->getGet('school_year');
        $schoolYear = $this->normalizeSchoolYear($schoolYearParam) ?? $this->schoolYear;
        /*
    // OPTIONAL (recommended): ensure the classSectionId belongs to this teacher for the active term
    $updatedBy = (int) (session()->get('user_id') ?? 0);
    if ($updatedBy > 0) {
        // If you have a TeacherClassModel with new schema (position = 'main' or 'ta'):
        $isOwned = $this->teacherClassModel
            ->where('teacher_id', $updatedBy)
            ->where('class_section_id', $classSectionId)
            ->where('school_year', $this->schoolYear)
            ->where('semester', $this->semester)
            ->countAllResults() > 0;

        if (!$isOwned) {
            return redirect()->back()->with('status', 'You do not have access to that class section.');
        }
    }
*/
        // Persist chosen class section in the session
        session()->set('class_section_id', $classSectionId);

        // Load data for the view
        $semester = $this->getSelectedSemester();
        $homeworkScores  = $this->getHomeworkScoresByStudent($classSectionId, $semester, $schoolYear);
        $students        = $this->getStudentsByClassSectionAndYear($classSectionId, $schoolYear);
        $homeworkHeaders = $this->getHomeworkHeaders($classSectionId, $semester, $schoolYear);
        $scoresLocked    = $this->isScoresLocked($classSectionId, $semester, $schoolYear);

        // Render
        return view('grading/homework', [
            'homeworkScores'  => $homeworkScores,
            'students'        => $students,
            'semester'        => $semester,
            'schoolYear'      => $schoolYear,
            'homeworkHeaders' => $homeworkHeaders,
            'classSectionId'  => $classSectionId,
            'hasHomeworkCols' => !empty($homeworkHeaders),
            'isManagement'    => true,
            'scoresLocked'    => $scoresLocked,
        ]);
    }


    public function updateHomework()
    {
        $scores       = $this->request->getPost('scores');
        $studentIds   = $this->request->getPost('student_ids');
        $semester     = $this->request->getPost('semester') ?? $this->getSelectedSemester();
        $schoolYear   = $this->request->getPost('school_year') ?? $this->schoolYear;

        $updatedBy = $this->request->getPost('teacher_id') ?? session()->get('user_id');
        $classSectionId = $this->request->getPost('class_section_id') ?? session()->get('class_section_id'); // persisted in showHomeworkMngt
        $classSectionIdInt = (int) ($classSectionId ?? 0);
        if ($classSectionIdInt > 0 && $this->isScoresLocked($classSectionIdInt, $semester, $schoolYear)) {
            return redirect()->back()->with('error', 'Scores are locked for this class. Unlock to edit.');
        }

        if ($scores && $studentIds && $semester && $schoolYear && $classSectionId) {
            $this->updateHomeworkScores($scores, $updatedBy, $classSectionId);
            session()->setFlashdata('status', 'Homework scores updated successfully.');

            // ⬇️ Directly call the method and return its view
            return $this->showHomeworkMngt($updatedBy);
        }

        $studentTeacherInfo = $this->studentModel->getStudentInfoByClassSectionId($classSectionId);
        // Call the updateScoresForStudents method
        try {

            $this->semesterScoreService->updateScoresForStudents($studentTeacherInfo, $semester, $schoolYear);
        } catch (RuntimeException $e) {
            // Handle error
        }
        return redirect()->back()->with('status', 'Failed to update scores.');
    }

    private function isScoresLocked(int $classSectionId, string $semester, string $schoolYear): bool
    {
        return $this->gradingLockModel->isLocked($classSectionId, $semester, $schoolYear);
    }

    // ──────────────── Helpers ────────────────

    private function saveHomeworkScores(array $scores, array $studentIds, string $semester, string $schoolYear, int $updatedBy, int $classSectionId)
    {
        $now = utc_now();

        foreach ($studentIds as $studentId) {
            if (!isset($scores[$studentId])) {
                continue;
            }

            foreach ($scores[$studentId] as $index => $score) {
                $isBlank = $score === null || (is_string($score) && trim($score) === '');

                // Check if the record exists
                $existing = $this->homeworkModel
                    ->where('student_id', $studentId)
                    ->where('homework_index', $index)
                    ->where('semester', $semester)
                    ->where('school_year', $schoolYear)
                    ->where('class_section_id', $classSectionId)
                    //->where('teacher_id', $updatedBy)
                    ->first();

                if ($isBlank) {
                    if ($existing) {
                        $this->homeworkModel->update($existing['id'], [
                            'score'      => null,
                            'updated_by' => $updatedBy,
                            'updated_at' => $now,
                        ]);
                    } else {
                        $this->homeworkModel->insert([
                            'student_id'       => $studentId,
                            'class_section_id' => $classSectionId,
                            'updated_by'       => $updatedBy,
                            'homework_index'   => $index,
                            'score'            => null,
                            'semester'         => $semester,
                            'school_year'      => $schoolYear,
                            'created_at'       => $now,
                            'updated_at'       => $now,
                        ]);
                    }
                    continue;
                }

                $data = [
                    'student_id'       => $studentId,
                    'class_section_id' => $classSectionId,
                    'updated_by'       => $updatedBy,
                    'homework_index'   => $index,
                    'score'            => is_numeric($score) ? floatval($score) : null,
                    'semester'         => $semester,
                    'school_year'      => $schoolYear,
                    'updated_at'       => $now,
                ];

                if ($existing) {
                    $this->homeworkModel->update($existing['id'], $data);
                } else {
                    $data['created_at'] = $now;
                    $data['school_id'] = ''; // Set if needed
                    $this->homeworkModel->insert($data);
                }
            }
        }
    }

    private function getStudentsByClassSectionAndYear($classSectionId, $schoolYear)
    {
        // Step 1: Get student IDs from student_class table
        $studentClassRows = $this->studentClassModel
            ->select('student_id')
            ->distinct()
            ->where('class_section_id', $classSectionId)
            ->where('school_year', $schoolYear)
            ->findAll();

        $studentIds = array_column($studentClassRows, 'student_id');

        if (empty($studentIds)) {
            return []; // No students found
        }

        // Step 2: Get student data from students table
        $students = $this->studentModel
            ->whereIn('id', $studentIds)
            ->where('is_active', 1)
            ->orderBy('lastname', 'ASC')
            ->findAll();

        return $students;
    }

    private function getClassSectionIdForTeacher($updatedBy, ?string $schoolYear = null, ?string $semester = null)
    {
        $builder = $this->teacherClassModel->where('teacher_id', $updatedBy);
        if ($schoolYear !== null && $schoolYear !== '') {
            $builder->where('school_year', $schoolYear);
        }
        if ($semester !== null && $semester !== '') {
            $builder->where('semester', $semester);
        }
        $class = $builder->first();
        return $class['class_section_id'] ?? null;
    }


    private function getHomeworkScoresByStudent($classSectionId, $semester, $schoolYear)
    {
        $semVariants = $this->getSemesterVariants($semester);
        $rows = $this->homeworkModel
            ->select('student_id, homework_index, score')
            ->where('class_section_id', $classSectionId)
            ->whereIn('semester', $semVariants)
            ->where('school_year', $schoolYear)
            ->findAll();

        $studentScores = [];
        foreach ($rows as $row) {
            $studentId = $row['student_id'];
            $index = $row['homework_index'];
            $score = $row['score'];

            $studentScores[$studentId]['scores'][$index] = $score;
        }

        return $studentScores;
    }

    private function getStudentsWithHomeworkScores($classSectionId, $homeworkHeaders, $semester, $schoolYear)
    {
        $semVariants = $this->getSemesterVariants($semester);
        $studentClasses = $this->studentClassModel->getClassStudents($classSectionId, $schoolYear, null);
        $students = [];

        foreach ($studentClasses as $sc) {
            $student = $this->studentModel
                ->where('id', $sc['student_id'])
                ->where('is_active', 1)
                ->first();
            if (!$student) continue;

            $scores = [];
                foreach ($homeworkHeaders as $ids) {
                    $entry = $this->homeworkModel->where('homework_index', $ids)
                        ->where('student_id', $sc['student_id'])
                        ->where('class_section_id', $classSectionId)
                        ->whereIn('semester', $semVariants)
                        ->where('school_year', $schoolYear)
                        ->first();
                // Keep null/blank when no entry exists yet
                $scores[$ids] = $entry['score'] ?? null;
            }

            $students[] = [
                'student_id' => $sc['student_id'],
                'firstname'  => $student['firstname'],
                'lastname'   => $student['lastname'],
                'scores'     => $scores
            ];
        }

        usort($students, fn($a, $b) => strcmp($a['lastname'], $b['lastname']) ?: strcmp($a['firstname'], $b['firstname']));
        return $students;
    }

    private function getHomeworkHeaders($classSectionId, $semester, $schoolYear)
    {

        $semVariants = $this->getSemesterVariants($semester);
        $rows = $this->homeworkModel
            ->select('homework_index')
            ->where('class_section_id', $classSectionId)
            //->where('teacher_id', $updatedBy)
            ->whereIn('semester', $semVariants)
            ->where('school_year', $schoolYear)
            ->orderBy('homework_index', 'ASC')
            ->findAll();

        $headers = [];

        foreach ($rows as $row) {
            $index = $row['homework_index'];
            if (!is_array($index)) {
                $headers[$index] = true;
            }
        }

        ksort($headers);
        return array_keys($headers);
    }

    private function getSemesterVariants(?string $semester): array
    {
        $raw = trim((string) $semester);
        $variants = [
            $raw,
            strtolower($raw),
            ucfirst(strtolower($raw)),
        ];
        $normalized = $this->normalizeSemesterSelection($raw);
        if ($normalized === 'fall') {
            $variants[] = 'First Semester';
            $variants[] = 'Semester 1';
            $variants[] = '1st Semester';
            $variants[] = 'Fall Semester';
        } elseif ($normalized === 'spring') {
            $variants[] = 'Second Semester';
            $variants[] = 'Semester 2';
            $variants[] = '2nd Semester';
            $variants[] = 'Spring Semester';
        }
        return array_values(array_unique(array_filter($variants, static fn($v) => $v !== '')));
    }

    private function getSelectedSemester(): string
    {
        $session = session();
        $selected = $session->get('teacher_scores_selected_semester');
        if (!empty($selected)) {
            return (string) $selected;
        }
        return $session->get('semester') ?? $this->semester;
    }

    private function normalizeSemesterSelection(?string $input): string
    {
        $value = strtolower(trim((string) $input));
        if ($value === 'fall' || str_contains($value, '1')) {
            return 'fall';
        }
        if ($value === 'spring' || str_contains($value, '2')) {
            return 'spring';
        }
        return '';
    }

    private function normalizeSchoolYear(?string $input): ?string
    {
        $value = trim((string) $input);
        if ($value === '') {
            return null;
        }
        if (preg_match('/^\\d{4}\\s*[-\\/]\\s*\\d{4}$/', $value)) {
            return preg_replace('/\\s+/', '', str_replace('/', '-', $value));
        }
        return null;
    }
}
