<?php

namespace App\Controllers\View;

use App\Models\UserModel;
use App\Models\TeacherModel;
use App\Models\StudentModel;
use App\Models\ClassSectionModel;
use App\Models\TeacherClassModel;
use App\Models\ConfigurationModel;
use App\Controllers\BaseController;
use App\Models\StudentClassModel;
use App\Models\StudentMedicalConditionModel;
use App\Models\StudentAllergyModel;
use App\Models\StaffAttendanceModel;
use App\Libraries\StaffTimeOffLinkService;
use App\Services\SemesterRangeService;
use CodeIgniter\Controller;


class TeacherController extends BaseController
{
    protected $db;
    protected $configModel;
    protected $semester;
    protected $schoolYear;
    protected $teacherClassModel;
    protected $studentClassModel;
    protected $teacherModel;
    protected $userModel;
    protected $medicalModel;
    protected $allergyModel;
    protected $staffAttendanceModel;

    public function __construct()
    {
        // Load the database service
        $this->db = \Config\Database::connect();
        // Check if the database connection is established
        if (!$this->db->connect()) {
            log_message('error', 'Database connection failed.');
            throw new \Exception('Database connection failed.');
        } else {
            log_message('info', 'Database connection successful.');
        }

        // Initialize the config model
        $this->configModel = new ConfigurationModel(); // Assuming ConfigModel is the model handling configurations
        $this->teacherClassModel = new TeacherClassModel();
        $this->studentClassModel = new StudentClassModel();
        $this->teacherModel = new TeacherModel();
        $this->userModel = new UserModel();
        $this->medicalModel = new StudentMedicalConditionModel();
        $this->allergyModel = new StudentAllergyModel();
        $this->staffAttendanceModel = new StaffAttendanceModel();

        // Retrieve the configuration values
        $this->semester = $this->configModel->getConfig('semester');
        $this->schoolYear = $this->configModel->getConfig('school_year');
    }


    public function classView()
    {
        try {
            log_message('debug', 'TeacherController::classView() method called');

            $user_id = session()->get('user_id');
            if (!$user_id) {
                log_message('error', 'User not logged in');
                return redirect()->to('user/login')->with('error', 'Please log in first');
            }

            // Fetch all assignments (as main or TA)
            $classes = $this->teacherClassModel->getClassAssignmentsByUserId($user_id, $this->schoolYear);

            if (empty($classes)) {
                log_message('info', 'No classes found for teacher ID: ' . $user_id);
                return redirect()->to('no-classes')->with('message', 'You do not have an assigned class yet. Please contact the administration.');
            }

            // Identify user and their role
            $user = $this->userModel->find($user_id);
            if (!$user) {
                log_message('error', 'User not found for ID: ' . $user_id);
                return redirect()->to('/error')->with('error', 'User not found');
            }

            $roles = $this->db->table('user_roles ur')
                ->select('r.name')
                ->join('roles r', 'r.id = ur.role_id')
                ->where('ur.user_id', $user_id)
                ->get()->getResultArray();

            $roleNames = array_map(fn($r) => $r['name'], $roles);

            if (in_array('teacher', $roleNames)) {
                $user['role_name'] = 'teacher';
            } elseif (in_array('teacher_assistant', $roleNames)) {
                $user['role_name'] = 'teacher_assistant';
            } else {
                log_message('error', 'Invalid role for user ID: ' . $user_id);
                return redirect()->to('/error')->with('error', 'Access denied');
            }

            // Collect class section IDs
            $classSectionIds = array_map('intval', array_column($classes, 'class_section_id'));
            $requestedClassId = (int)($this->request->getGet('class_section_id') ?? 0);
            $sessionClassId = (int)(session()->get('class_section_id') ?? 0);
            $activeClassSectionId = null;
            if ($requestedClassId && in_array($requestedClassId, $classSectionIds, true)) {
                $activeClassSectionId = $requestedClassId;
            } elseif ($sessionClassId && in_array($sessionClassId, $classSectionIds, true)) {
                $activeClassSectionId = $sessionClassId;
            } elseif (!empty($classSectionIds)) {
                $activeClassSectionId = $classSectionIds[0];
            }

            if ($activeClassSectionId) {
                session()->set('class_section_id', $activeClassSectionId);
            }
            $studentsData = [];

            if (!empty($classSectionIds)) {
                // 1) Fetch all students for the selected class sections
                $students = $this->studentClassModel->getStudentsByClassSectionIds($classSectionIds);

                if (!empty($students)) {
                    // 2) Collect unique student IDs
                    $studentIds = array_values(array_unique(array_map(
                        static fn(array $row) => (int) ($row['student_id'] ?? 0),
                        $students
                    )));
                    $studentIds = array_values(array_filter($studentIds));

                    // 3) Bulk fetch medical conditions & allergies grouped by student_id
                    $conditionsByStudent = !empty($studentIds)
                        ? $this->medicalModel->getMedicalByStudentIds($studentIds)   // [sid => [rows...]]
                        : [];
                    $allergiesByStudent  = !empty($studentIds)
                        ? $this->allergyModel->getAllergiesByStudentIds($studentIds) // [sid => [rows...]]
                        : [];

                    // 4) Attach only names/values (plus display strings) to each student
                    foreach ($students as $student) {
                        $sid = (int) ($student['student_id'] ?? 0);
                        $cid = (int) ($student['class_section_id'] ?? 0);

                        // Extract lists (arrays of strings)
                        $medList  = array_column($conditionsByStudent[$sid] ?? [], 'condition_name');
                        $algList  = array_column($allergiesByStudent[$sid]  ?? [], 'allergy');

                        // Keep arrays for logic if needed
                        $student['medical_conditions'] = $medList;
                        $student['allergies']          = $algList;

                        // Also provide display-ready strings so views don’t implode() themselves
                        $student['medical_conditions_text'] = implode(', ', $medList);
                        $student['allergies_text']          = implode(', ', $algList);
                        // Group under class section
                        $studentsData[$cid][] = $student;
                    }
                }
            }
            // Build assigned staff lists (all Main teachers and all TAs) per class section
            $assignedNames = [];
            if (!empty($classSectionIds)) {
                $rows = $this->db->table('teacher_class tc')
                    ->select('tc.class_section_id, tc.position, u.firstname, u.lastname')
                    ->join('users u', 'u.id = tc.teacher_id', 'inner')
                    ->whereIn('tc.class_section_id', $classSectionIds)
                    ->where('tc.school_year', $this->schoolYear)
                    ->orderBy('tc.class_section_id', 'ASC')
                    ->orderBy("FIELD(tc.position,'main','ta')", '', false)
                    ->orderBy('u.firstname', 'ASC')
                    ->get()->getResultArray();

                foreach ($rows as $r) {
                    $sid  = (int)($r['class_section_id'] ?? 0);
                    $pos  = strtolower((string)($r['position'] ?? ''));
                    $name = trim(($r['firstname'] ?? '') . ' ' . ($r['lastname'] ?? ''));
                    if ($sid === 0 || $name === '') continue;

                    if (in_array($pos, ['main', 'teacher'], true)) {
                        $assignedNames[$sid]['mains'][] = $name;
                    } elseif (in_array($pos, ['ta', 'assistant', 'teacher_assistant'], true)) {
                        $assignedNames[$sid]['tas'][] = $name;
                    } else {
                        $assignedNames[$sid]['others'][] = $name;
                    }
                }
            }

            // Log debug info
            log_message('debug', 'Classes: ' . print_r($classes, true));
            log_message('debug', 'Students Data: ' . print_r($studentsData, true));
            log_message('debug', 'Assigned Names: ' . print_r($assignedNames, true));

            // First class_section_id for default selection
            $class_section_id = $activeClassSectionId;

            return view('/teacher/class_view', [
                'teacher_name'     => $user['firstname'] . ' ' . $user['lastname'],
                'classes'          => $classes,
                'students'         => $studentsData[$class_section_id] ?? [],
                'studentsData'     => $studentsData,
                'class_section_id' => $class_section_id,
                'active_class_id'  => $class_section_id,
                // Backward compat: keep taNames for view fallback if needed
                'taNames'          => [],
                'assignedNames'    => $assignedNames,
            ]);
        } catch (\Exception $e) {
            log_message('error', 'Error in TeacherController::classView(): ' . $e->getMessage());
            return redirect()->to('/error')->with('error', 'An error occurred. Please try again later.');
        }
    }

    /**
     * Switch the active class for the logged-in teacher.
     * Validates the requested class belongs to the teacher for the current term.
     */
    public function switchClass()
    {
        $userId = (int)(session()->get('user_id') ?? 0);
        if (!$userId) {
            return redirect()->back()->with('error', 'Not authenticated.');
        }

        $redirectTo = $this->request->getPost('redirect_to') ?? base_url('/teacher_dashboard');
        $requested  = (int)$this->request->getPost('class_section_id');

        $assignments = $this->teacherClassModel->getClassAssignmentsByUserId(
            $userId,
            (string)$this->schoolYear,
            (string)$this->semester
        );
        $allowedIds = array_map(static fn($a) => (int)($a['class_section_id'] ?? 0), $assignments);
        $allowedIds = array_values(array_filter(array_unique($allowedIds)));

        if ($requested && in_array($requested, $allowedIds, true)) {
            session()->set('class_section_id', $requested);
        } else {
            return redirect()->to($redirectTo)->with('error', 'You are not assigned to that class.');
        }

        return redirect()->to($redirectTo);
    }

    public function noClasses()
    {
        return view('/teacher/no_classes');
    }


    public function teacherClassAssignment()
    {
        $selectedYear = trim((string)($this->request->getGet('schoolYear') ?? $this->request->getGet('school_year') ?? ''));
        if ($selectedYear === '') {
            $selectedYear = (string)($this->schoolYear ?? 'Not Set');
        }

        // Build distinct school years from classSection (fallback to configured year)
        try {
            $yearsRows = $this->db->table('classSection')
                ->distinct()
                ->select('school_year')
                ->orderBy('school_year', 'DESC')
                ->get()->getResultArray();
            $schoolYears = array_values(array_filter(array_map(static function ($r) {
                return isset($r['school_year']) ? (string)$r['school_year'] : null;
            }, $yearsRows)));
            if (empty($schoolYears) && !empty($this->schoolYear)) {
                $schoolYears = [(string)$this->schoolYear];
            }
        } catch (\Throwable $e) {
            $schoolYears = !empty($this->schoolYear) ? [(string)$this->schoolYear] : [];
        }

        return view('administrator/teacher_class_assignment', [
            'schoolYear'     => (string)$selectedYear,
            'schoolYears'    => $schoolYears,
            'currentYear'    => (string)($this->schoolYear ?? ''),
            'isCurrentYear'  => ((string)$selectedYear === (string)($this->schoolYear ?? '')),
            'missingYear'    => empty($this->schoolYear),
            'apiListUrl'     => site_url('api/administrator/teacher-class/assignments'),
            'apiAssignUrl'   => site_url('api/administrator/teacher-class/assign'),
            'apiDeleteUrl'   => site_url('api/administrator/teacher-class/delete'),
            'csrfTokenName'  => csrf_token(),
            'csrfTokenValue' => csrf_hash(),
        ]);
    }

    private function buildTeacherClassAssignmentPayload(?string $forYear = null): array
    {
        $classSectionModel = new ClassSectionModel();
        $schoolYear = $forYear ?: ((string)($this->schoolYear ?? 'Not Set'));

        $teachers = $this->teacherModel->getTeachersAndTAs();
        // Prefer class sections for the selected year, fallback to all if none
        $classSections = $classSectionModel
            ->where('school_year', $schoolYear)
            ->orderBy('class_section_name', 'ASC')
            ->findAll();
        if (empty($classSections)) {
            $classSections = $classSectionModel->orderBy('class_section_name', 'ASC')->findAll();
        }

        $classNames = [];
        foreach ($classSections as $section) {
            $sectionId = (int)($section['class_section_id'] ?? $section['id'] ?? 0);
            if ($sectionId <= 0) {
                continue;
            }
            $classNames[$sectionId] = $section['class_section_name'] ?? ($section['name'] ?? 'N/A');
        }

        $assignments = $this->teacherClassModel
            ->where('school_year', $schoolYear)
            ->findAll();

        $assignmentMap = [];
        foreach ($assignments as $assign) {
            $teacherId = (int)($assign['teacher_id'] ?? 0);
            $sectionId = (int)($assign['class_section_id'] ?? 0);
            if ($teacherId <= 0 || $sectionId <= 0) {
                continue;
            }

            $role = strtolower((string)($assign['position'] ?? ''));
            if (!in_array($role, ['main', 'ta'], true)) {
                continue;
            }

            if (!isset($assignmentMap[$teacherId])) {
                $assignmentMap[$teacherId] = ['main' => [], 'ta' => []];
            }

            $assignmentMap[$teacherId][$role][] = [
                'section_id'         => $sectionId,
                'class_section_name' => $classNames[$sectionId] ?? 'N/A',
                'role'               => $role,
                'semester'           => (string)($assign['semester'] ?? $this->semester ?? ''),
                'school_year'        => (string)($assign['school_year'] ?? $schoolYear),
            ];
        }

        $teacherData = [];
        foreach ($teachers as $teacher) {
            $tid = (int)($teacher['id'] ?? 0);
            if ($tid <= 0) {
                continue;
            }

            $assigned = $assignmentMap[$tid] ?? ['main' => [], 'ta' => []];
            $firstName = $teacher['firstname'] ?? '';
            $lastName  = $teacher['lastname'] ?? '';
            $name = trim($firstName . ' ' . $lastName);
            if ($name === '') {
                $name = 'User#' . $tid;
            }

            $teacherData[] = [
                'teacher_id'       => $tid,
                'firstname'        => $firstName,
                'lastname'         => $lastName,
                'name'             => $name,
                'email'            => $teacher['email'] ?? '',
                'cellphone'        => $teacher['cellphone'] ?? '',
                'role'             => $teacher['role'] ?? '',
                'school_year'      => $this->schoolYear,
                'main_assignments' => $assigned['main'],
                'ta_assignments'   => $assigned['ta'],
            ];
        }

        $classesPayload = [];
        foreach ($classSections as $section) {
            $sectionId = (int)($section['class_section_id'] ?? $section['id'] ?? 0);
            if ($sectionId <= 0) {
                continue;
            }
            $classesPayload[] = [
                'class_section_id'   => $sectionId,
                'class_section_name' => $section['class_section_name'] ?? ($section['name'] ?? 'N/A'),
            ];
        }

        return [
            'school_year' => $schoolYear,
            'teachers'    => $teacherData,
            'classes'     => $classesPayload,
        ];
    }

    private function respondAssignmentJson(array $payload, int $statusCode = 200)
    {
        $payload['csrf_token'] = csrf_token();
        $payload['csrf_hash']  = csrf_hash();
        return $this->response->setStatusCode($statusCode)->setJSON($payload);
    }

    public function teacherClassAssignmentsApi()
    {
        $forYear = trim((string)($this->request->getGet('schoolYear') ?? $this->request->getGet('school_year') ?? ''));
        $payload = $this->buildTeacherClassAssignmentPayload($forYear !== '' ? $forYear : null);
        $payload['ok'] = true;
        return $this->respondAssignmentJson($payload);
    }





    public function refreshTeacherAssignments()
    {
        $teacherAssignments = $this->teacherClassModel->findAll();

        // Return the data as JSON
        return $this->response->setJSON([
            'status' => 'success',
            'data' => $teacherAssignments
        ]);
    }

    public function messageTeacher()
    {
        return view('/teacher/teacher_message');
    }

    public function assignmentTeacher()
    {
        return view('/teacher/teacher_assignment');
    }


    private function handleAssignClassTeacher(array $input): array
    {
        $teacherId      = (int)($input['teacher_id'] ?? 0);
        $classSectionId = (int)($input['class_section_id'] ?? 0);
        $teacherRole    = $input['teacher_role'] ?? null;
        $loggedInUserId = (int)(session()->get('user_id') ?? 0);
        $currentDateTime = utc_now();

        if ($teacherId <= 0 || $classSectionId <= 0) {
            return ['ok' => false, 'status' => 'error', 'message' => 'Missing required parameters for assignment.'];
        }

        if (empty($this->schoolYear)) {
            return ['ok' => false, 'status' => 'error', 'message' => 'School year not configured.'];
        }

        if ($teacherRole === null || $teacherRole === '') {
            $teacherRole = $this->userModel->getUserRole($teacherId);
        }

        $isAssistant = strtolower((string)$teacherRole) === 'teacher_assistant';
        $position = $isAssistant ? 'ta' : 'main';

        $alreadyAssigned = $this->teacherClassModel->where([
            'teacher_id'       => $teacherId,
            'class_section_id' => $classSectionId,
            'position'         => $position,
            'school_year'      => $this->schoolYear,
        ])->first();

        if ($alreadyAssigned) {
            return ['ok' => false, 'status' => 'info', 'message' => 'This teacher is already assigned to this class with the same role.'];
        }

        $insertData = [
            'teacher_id'       => $teacherId,
            'class_section_id' => $classSectionId,
            'position'         => $position,
            'school_year'      => $this->schoolYear,
            'created_at'       => $currentDateTime,
            'updated_at'       => $currentDateTime,
            'updated_by'       => $loggedInUserId,
        ];

        try {
            $this->teacherClassModel->insert($insertData);
        } catch (\Throwable $e) {
            log_message('error', 'assignClassTeacher failed: ' . $e->getMessage());
            return ['ok' => false, 'status' => 'error', 'message' => 'Unable to assign class. Please try again.'];
        }

        return [
            'ok'      => true,
            'status'  => 'success',
            'message' => 'Class assigned to ' . ($isAssistant ? 'Teacher Assistant' : 'Main Teacher') . ' successfully.',
            'position'=> $position,
        ];
    }

    public function assignClassTeacher()
    {
        $result = $this->handleAssignClassTeacher([
            'teacher_id'       => $this->request->getPost('teacher_id'),
            'class_section_id' => $this->request->getPost('class_section_id'),
            'teacher_role'     => $this->request->getPost('teacher_role'),
        ]);

        if ($this->request->wantsJSON() || $this->request->isAJAX()) {
            $statusCode = $result['ok'] ? 200 : 422;
            return $this->respondAssignmentJson($result, $statusCode);
        }

        session()->setFlashdata($result['status'], $result['message']);
        return redirect()->to('administrator/teacher_class_assignment');
    }

    public function assignClassTeacherApi()
    {
        $payload = $this->request->getJSON(true) ?? [];
        $result = $this->handleAssignClassTeacher($payload);
        $statusCode = $result['ok'] ? 200 : 422;
        return $this->respondAssignmentJson($result, $statusCode);
    }

    // Functions for teacher assignments
    private function createNewAssignment($teacherClassModel, $teacherId, $classSectionId, $loggedInUserId, $currentDateTime)
    {
        // Get the teacher's role to determine position
        $teacherRole = $this->userModel->getUserRole($teacherId);
        $position = (strtolower($teacherRole) === 'teacher_assistant') ? 'ta' : 'main';

        // Prevent assigning TA without a main teacher already present
        if ($position === 'ta') {
            $mainExists = $teacherClassModel->where([
                'class_section_id' => $classSectionId,
                'position'         => 'main',
                'school_year'      => $this->schoolYear,
            ])->first();

            if (!$mainExists) {
                session()->setFlashdata('error', 'Cannot assign a Teacher Assistant without a Main Teacher assigned first.');
                return $this->teacherClassAssignment();
            }
        }

        // Check for position conflict before inserting
        $positionConflict = $teacherClassModel->where([
            'class_section_id' => $classSectionId,
            'position'         => $position,
            'school_year'      => $this->schoolYear,
        ])->first();

        if ($positionConflict) {
            session()->setFlashdata('error', ucfirst($position) . ' is already assigned to this class.');
            return $this->teacherClassAssignment();
        }

        // Insert new record
        $teacherClassModel->insert([
            'teacher_id'       => $teacherId,
            'class_section_id' => $classSectionId,
            'position'         => $position,
            'school_year'      => $this->schoolYear,
            'updated_by'       => $loggedInUserId,
            'created_at'       => $currentDateTime,
            'updated_at'       => $currentDateTime
        ]);

        session()->setFlashdata('success', 'Teacher assigned successfully.');
        return $this->teacherClassAssignment();
    }


    private function updateTeacherAssignment($existingClass, $teacherId, $teacherClassModel, $loggedInUserId, $currentDateTime)
    {
        $teacherRole = $this->userModel->getUserRole($teacherId);
        $position = (strtolower($teacherRole) === 'teacher_assistant') ? 'ta' : 'main';

        // Check if same class_section_id already has a main/ta
        $positionConflict = $teacherClassModel->where([
            'class_section_id' => $existingClass['class_section_id'],
            'position'         => $position,
            'school_year'      => $this->schoolYear,
        ])->first();

        if ($positionConflict && $positionConflict['teacher_id'] !== $teacherId) {
            session()->setFlashdata('error', ucfirst($position) . ' already assigned to this class.');
            return $this->teacherClassAssignment();
        }

        $teacherClassModel->update($existingClass['id'], [
            'teacher_id' => $teacherId,
            'position'   => $position,
            'updated_by' => $loggedInUserId,
            'updated_at' => $currentDateTime
        ]);

        session()->setFlashdata('success', ucfirst($position) . ' reassigned successfully.');
        return $this->teacherClassAssignment();
    }

    private function clearupdateTeacherAssignment($existingAssignment, $teacherId, $teacherClassModel, $loggedInUserId, $currentDateTime)
    {
        // Step 1: Delete all TAs for this class_section + school_year
        $teacherClassModel->where([
            'class_section_id' => $existingAssignment['class_section_id'],
            'position'         => 'ta',
            'school_year'      => $this->schoolYear,
        ])->delete();

        // Step 2: Update the main teacher assignment
        $teacherClassModel->update($existingAssignment['id'], [
            'teacher_id' => $teacherId,
            'position'   => 'main',
            'updated_by' => $loggedInUserId,
            'updated_at' => $currentDateTime
        ]);

        session()->setFlashdata('success', 'Main teacher reassigned and assistants cleared.');
        return $this->teacherClassAssignment();
    }


    private function updateTeacherAssignmentForSameClass($existingClass, $teacherClassModel, $loggedInUserId, $currentDateTime)
    {
        // No changes to assistants needed — schema uses separate rows per person
        $teacherClassModel->update($existingClass['id'], [
            'updated_by' => $loggedInUserId,
            'updated_at' => $currentDateTime
        ]);

        session()->setFlashdata('info', 'This class is already assigned to the teacher.');
        return $this->teacherClassAssignment();
    }

    private function assignNewAssistant($existingClass, $teacherClassModel, $teacherId, $classSectionId, $loggedInUserId, $currentDateTime)
    {
        // Check if TA already assigned to this class for the current school year
        $alreadyAssigned = $teacherClassModel->where([
            'teacher_id' => $teacherId,
            'class_section_id' => $classSectionId,
            'school_year' => $this->schoolYear,
            'position' => 'ta'
        ])->first();

        if ($alreadyAssigned) {
            session()->setFlashdata('info', 'This assistant is already assigned to the class.');
            return $this->teacherClassAssignment();
        }

        // Insert a new row for the assistant
        $teacherClassModel->insert([
            'teacher_id' => $teacherId,
            'class_section_id' => $classSectionId,
            'school_year' => $this->schoolYear,
            'position' => 'ta',
            'created_at' => $currentDateTime,
            'updated_at' => $currentDateTime,
            'updated_by' => $loggedInUserId
        ]);

        session()->setFlashdata('success', 'Assistant assigned successfully.');
        return $this->teacherClassAssignment();
    }

    private function updateAssistantAssignment($existingAssignment, $classSectionId, $teacherClassModel, $loggedInUserId, $currentDateTime)
    {
        $teacherClassModel->update($existingAssignment['id'], [
            'class_section_id' => $classSectionId,
            'updated_by' => $loggedInUserId,
            'updated_at' => $currentDateTime
        ]);

        session()->setFlashdata('success', 'Assistant reassigned successfully.');
        return $this->teacherClassAssignment();
    }

    private function updateAssistantForSameClass($existingAssignment, $existingClass, $teacherId, $teacherClassModel, $loggedInUserId, $currentDateTime)
    {
        // If the assignment already exists and class is the same, flash info
        if ($existingAssignment['class_section_id'] == $existingClass['class_section_id']) {
            session()->setFlashdata('info', 'This assistant is already assigned to the selected class.');
            return $this->teacherClassAssignment();
        }

        // Otherwise, update to correct class_section
        $teacherClassModel->update($existingAssignment['id'], [
            'class_section_id' => $existingClass['class_section_id'],
            'updated_by' => $loggedInUserId,
            'updated_at' => $currentDateTime
        ]);

        session()->setFlashdata('success', 'Assistant moved to the correct class.');
        return $this->teacherClassAssignment();
    }

    private function handleDeleteAssignment(array $input): array
    {
        $teacherId      = (int)($input['teacher_id'] ?? 0);
        $classSectionId = (int)($input['class_section_id'] ?? 0);
        $position       = strtolower((string)($input['position'] ?? ''));

        if ($teacherId <= 0 || $classSectionId <= 0 || !in_array($position, ['main', 'ta'], true)) {
            return ['ok' => false, 'status' => 'error', 'message' => 'Missing or invalid data for deletion.'];
        }

        if (empty($this->schoolYear)) {
            return ['ok' => false, 'status' => 'error', 'message' => 'School year not configured.'];
        }

        $requestedSchoolYear = trim((string)($input['school_year'] ?? ''));
        $schoolYear = $requestedSchoolYear !== '' ? $requestedSchoolYear : $this->schoolYear;

        if ($schoolYear === '') {
            return ['ok' => false, 'status' => 'error', 'message' => 'School year not configured.'];
        }

        $assignment = $this->teacherClassModel
            ->where('teacher_id', $teacherId)
            ->where('class_section_id', $classSectionId)
            ->where('school_year', $schoolYear)
            ->where('position', $position)
            ->first();

        if (!$assignment) {
            return ['ok' => false, 'status' => 'error', 'message' => 'Assignment not found.'];
        }

        try {
            $this->teacherClassModel->delete($assignment['id']);
        } catch (\Throwable $e) {
            log_message('error', 'deleteAssignment failed: ' . $e->getMessage());
            return ['ok' => false, 'status' => 'error', 'message' => 'Unable to remove assignment. Please try again.'];
        }

        return [
            'ok'      => true,
            'status'  => 'success',
            'message' => ucfirst($position) . ' assignment removed successfully.',
        ];
    }

    public function deleteAssignment()
    {
        $result = $this->handleDeleteAssignment([
            'teacher_id'       => $this->request->getPost('teacher_id'),
            'class_section_id' => $this->request->getPost('class_section_id'),
            'position'         => $this->request->getPost('position'),
        ]);

        if ($this->request->wantsJSON() || $this->request->isAJAX()) {
            $statusCode = $result['ok'] ? 200 : 422;
            return $this->respondAssignmentJson($result, $statusCode);
        }

        session()->setFlashdata($result['status'], $result['message']);
        return redirect()->to('administrator/teacher_class_assignment');
    }

    public function deleteAssignmentApi()
    {
        $payload = $this->request->getJSON(true) ?? [];
        $result = $this->handleDeleteAssignment($payload);
        $statusCode = $result['ok'] ? 200 : 422;
        return $this->respondAssignmentJson($result, $statusCode);
    }

    /**
     * Compute all allowed absence dates (Sundays) for the configured school year
     * limited to future dates from today, within Sep (start year) to May (end year).
     */
    private function allowedAbsenceDates(): array
    {
        $todayStr = local_date(utc_now(), 'Y-m-d');
        try { $today = new \DateTimeImmutable($todayStr); } catch (\Throwable $e) { $today = new \DateTimeImmutable(); }

        $sy = (string)($this->schoolYear ?? '');
        $startYear = null; $endYear = null;
        if (preg_match('/^(\d{4})\D+(\d{4})$/', $sy, $m)) {
            $startYear = (int)$m[1];
            $endYear   = (int)$m[2];
        } else {
            // Fallback based on current date
            $cy = (int)date('Y');
            $cm = (int)date('n');
            if ($cm >= 9) { // Sep-Dec
                $startYear = $cy;
                $endYear   = $cy + 1;
            } else { // Jan-Aug
                $startYear = $cy - 1;
                $endYear   = $cy;
            }
        }

        try {
            $start = new \DateTimeImmutable(sprintf('%04d-09-01', $startYear));
            $end   = new \DateTimeImmutable(sprintf('%04d-05-31', $endYear));
        } catch (\Throwable $e) {
            return [];
        }

        // Clamp start to today if in range
        if ($start < $today) {
            $start = $today;
        }

        // Iterate and collect Sundays in range [start..end]
        $dates = [];
        for ($cursor = $start; $cursor <= $end; $cursor = $cursor->modify('+1 day')) {
            if ((int)$cursor->format('w') === 0) { // Sunday
                $dates[] = $cursor->format('Y-m-d');
            }
        }

        return $dates;
    }

    /**
     * Show self-service absence/vacation page for the logged-in teacher/TA.
     * Lists only the current user and allows selecting days to mark as absent with a reason.
     */
    public function absenceForm()
    {
        $userId = (int)(session()->get('user_id') ?? 0);
        if ($userId <= 0) {
            return redirect()->to('login')->with('error', 'Please log in first.');
        }

        $teacher = $this->userModel->find($userId);
        $displayName = $teacher ? trim(($teacher['firstname'] ?? '') . ' ' . ($teacher['lastname'] ?? '')) : 'Unknown';

        $semester   = (string)($this->semester   ?? '');
        $schoolYear = (string)($this->schoolYear ?? '');

        // Fetch existing self-reported staff attendance rows for this user (current term)
        $existing = $this->staffAttendanceModel
            ->where('user_id', $userId)
            ->where('semester', $semester)
            ->where('school_year', $schoolYear)
            ->orderBy('date', 'DESC')
            ->findAll();

        return view('/teacher/absence_vacation', [
            'teacher_name' => $displayName,
            'semester'     => $semester,
            'schoolYear'   => $schoolYear,
            'existing'     => $existing,
            'availableDates' => $this->allowedAbsenceDates(),
        ]);
    }

    /**
     * Save absence/vacation selections for the logged-in teacher.
     * Writes to staff_attendance as status=absent with a provided reason.
     */
    public function submitAbsence()
    {
        $userId = (int)(session()->get('user_id') ?? 0);
        if ($userId <= 0) {
            return redirect()->to('login')->with('error', 'Please log in first.');
        }

        $semester   = (string)($this->semester   ?? '');
        $schoolYear = (string)($this->schoolYear ?? '');
        if ($schoolYear === '') {
            return redirect()->to('/teacher/absence')->with('status', 'error')->with('message', 'Semester or school year not configured.');
        }
        $semesterResolver = new SemesterRangeService($this->configModel);

        // Gather inputs
        $dates      = (array)($this->request->getPost('dates') ?? []);
        $reasonType = trim((string)($this->request->getPost('reason_type') ?? ''));
        $reasonText = trim((string)($this->request->getPost('reason') ?? ''));

        if ($reasonText === '') {
            return redirect()->to('/teacher/absence')
                ->with('status', 'error')
                ->with('message', 'Reason is required.');
        }

        // Build reason string (combine category + text when type is present)
        $reasonBase = ($reasonType !== '') ? strtolower($reasonType) : '';
        $reason     = $reasonBase !== '' ? ($reasonBase . ': ' . $reasonText) : $reasonText;

        // Enforce allowed Sundays list (future Sundays in Sep..May for the term)
        $allowedDates = $this->allowedAbsenceDates();
        $allowedSet = array_fill_keys($allowedDates, true);

        // Find one role for logging (optional field)
        $roleName = $this->userModel->getUserRole($userId) ?: null;

        // Validate dates and save
        $saved = 0; $invalid = [];
        $savedDates = [];
        // de-duplicate selected dates
        $dates = array_values(array_unique(array_map('strval', $dates)));
        foreach ($dates as $d) {
            $d = trim((string)$d);
            if ($d === '') continue;
            $dt = date_create_from_format('Y-m-d', $d);
            if (!$dt || $dt->format('Y-m-d') !== $d || empty($allowedSet[$d])) {
                $invalid[] = $d;
                continue;
            }

            $semesterForDate = $semesterResolver->getSemesterForDate($d);
            if ($semesterForDate === '') {
                $semesterForDate = $semester;
            }

            $ok = $this->staffAttendanceModel->upsertOne(
                userId: $userId,
                roleName: $roleName,
                date: $d,
                semester: $semesterForDate,
                schoolYear: $schoolYear,
                status: StaffAttendanceModel::STATUS_ABSENT,
                reason: $reason,
                editorId: $userId
            );
            if ($ok) { $saved++; $savedDates[] = $d; }
        }

        if (!empty($invalid)) {
            return redirect()->to('/teacher/absence')
                ->with('status', 'error')
                ->with('message', 'Invalid dates: ' . implode(', ', $invalid));
        }

        // Send notification email to principal with request details
        try {
            $user = $this->userModel->find($userId) ?: [];
            $fullName = trim(($user['firstname'] ?? '') . ' ' . ($user['lastname'] ?? '')) ?: 'Unknown';
            $userEmail = $user['email'] ?? '';
            $role      = $roleName ?: 'staff';
            $dateList  = !empty($savedDates) ? implode(', ', $savedDates) : implode(', ', $dates);

            // If teacher/TA, include assigned class(es) for current term
            $assignedText = '-';
            if (in_array(strtolower((string)$roleName), ['teacher', 'teacher_assistant'], true)) {
                try {
                    $assignments = $this->teacherClassModel->getClassAssignmentsByUserId($userId, $schoolYear, $semester);
                    if (!empty($assignments)) {
                        $parts = [];
                        foreach ($assignments as $as) {
                            $name = (string)($as['class_section_name'] ?? '');
                            $r    = (string)($as['teacher_role'] ?? '');
                            if ($name !== '') {
                                $parts[] = $r ? ($name . ' (' . $r . ')') : $name;
                            }
                        }
                        if (!empty($parts)) {
                            $assignedText = implode(', ', $parts);
                        } else {
                            $assignedText = 'No assigned class';
                        }
                    } else {
                        $assignedText = 'No assigned class';
                    }
                } catch (\Throwable $e) {
                    $assignedText = 'N/A';
                }
            }

            $subject = sprintf('TimeOff Request: %s (%s) — %s', $fullName, ucfirst((string)$role), $dateList ?: 'No dates');
            $submittedAt = utc_now();

            $body = '<div style="font-family:Arial,Helvetica,sans-serif;font-size:14px;line-height:1.5;">'
                  . '<h3 style="margin:0 0 8px;">New TimeOff Request</h3>'
                  . '<p style="margin:0 0 12px;">A staff time-off request was submitted from the teacher portal.</p>'
                  . '<table cellpadding="6" cellspacing="0" style="border-collapse:collapse;">'
                  . '<tr><td><strong>Name</strong></td><td>' . esc($fullName) . '</td></tr>'
                  . '<tr><td><strong>Email</strong></td><td>' . esc($userEmail) . '</td></tr>'
                  . '<tr><td><strong>Role</strong></td><td>' . esc((string)$role) . '</td></tr>'
                  . '<tr><td><strong>Semester</strong></td><td>' . esc($semester) . '</td></tr>'
                  . '<tr><td><strong>School Year</strong></td><td>' . esc($schoolYear) . '</td></tr>'
                  . '<tr><td><strong>Reason Type</strong></td><td>' . esc($reasonType ?: '-') . '</td></tr>'
                  . '<tr><td><strong>Reason</strong></td><td>' . esc($reasonText) . '</td></tr>'
                  . '<tr><td><strong>Dates</strong></td><td>' . esc($dateList ?: '-') . '</td></tr>'
                  . (in_array(strtolower((string)$roleName), ['teacher','teacher_assistant'], true)
                        ? '<tr><td><strong>Assigned Class(es)</strong></td><td>' . esc($assignedText) . '</td></tr>'
                        : '')
                  . '<tr><td><strong>Submitted At</strong></td><td>' . esc($submittedAt) . '</td></tr>'
                  . '</table>'
                  . '</div>';

            $linkService = new StaffTimeOffLinkService();
            $token = $linkService->createToken([
                'uid'          => $userId,
                'email'        => $userEmail,
                'name'         => $fullName,
                'role'         => $role,
                'dates'        => $dateList ?: '-',
                'reason'       => $reasonText,
                'reason_type'  => $reasonType,
                'submitted_at' => $submittedAt,
                'origin'       => 'teacher portal',
            ]);
            $notifyUrl = base_url('timeoff/notify/' . rawurlencode($token));
            $body .= '<p style="margin-top:16px;">Click <a href="' . esc($notifyUrl) . '">Send confirmation email to '
                  . esc($fullName) . '</a> so the staff member is notified automatically. '
                  . 'This link expires in 14 days.</p>';

            // Use configured EmailService with notifications sender profile
            $mailer = \Config\Services::emailService();
            $principalEmail = env('PRINCIPAL_EMAIL') ?: 'principal@alrahmaisgl.org';
            $mailer->send($principalEmail, $subject, $body, 'notifications');
        } catch (\Throwable $e) {
            log_message('error', 'Failed to send TimeOff email: ' . $e->getMessage());
        }

        return redirect()->to('/teacher/absence')
            ->with('status', 'success')
            ->with('message', $saved . ' day(s) saved as absent.');
    }
}
