<?php

namespace App\Controllers\View;

use App\Models\CurrentFlagModel;
use App\Models\FlagModel;
use App\Models\StudentModel;
use App\Models\ClassSectionModel;
use App\Models\StudentClassModel;
use App\Models\ConfigurationModel;

use CodeIgniter\Controller;


class FlagController extends Controller
{
    protected $userModel;
    protected $db;

    public function __construct()
    {
        $this->db = \Config\Database::connect();
        //$this->userModel = new UserModel();
        helper(['url', 'form']);
    }

    public function index()
    {
        $currentFlagModel = new CurrentFlagModel();
        $classSectionModel = new ClassSectionModel();
        $studentClassModel = new StudentClassModel();
        $configModel = new ConfigurationModel();

        // Format grades with id and name for passing to the view
        $grades = [];

        // Retrieve flags and class sections that currently have active students
        $schoolYear = $configModel->getConfig('school_year');
        if ((string)$schoolYear !== '' && $this->db->fieldExists('school_year', 'current_flag')) {
            $currentFlagModel->where('school_year', (string)$schoolYear);
        }
        $flags = $currentFlagModel->findAll();
        $studentCounts = $studentClassModel->getStudentCountsBySection($schoolYear);
        $classSections = [];

        if (!empty($studentCounts)) {
            $classSectionIdsWithStudents = array_keys($studentCounts);
            $classSections = $classSectionModel
                ->orderBy('class_section_name', 'ASC')
                ->whereIn('class_section_id', $classSectionIdsWithStudents)
                ->findAll();
        }

        foreach ($classSections as $section) {
            $grades[] = [
                'id' => $section['class_section_id'],
                'name' => $section['class_section_name']
            ];
        }

        // Map updater user IDs to display names for the view
        $updaterIds = [];
        foreach ($flags as $flag) {
            foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
                if (!empty($flag[$key])) {
                    $updaterIds[(int)$flag[$key]] = true;
                }
            }
        }

        $updaterMap = [];
        if (!empty($updaterIds)) {
            $rows = $this->db->table('users')
                ->select('id, firstname, lastname')
                ->whereIn('id', array_keys($updaterIds))
                ->get()
                ->getResultArray();

            foreach ($rows as $row) {
                $name = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
                $updaterMap[(int)$row['id']] = $name !== '' ? $name : ('User #' . $row['id']);
            }
        }

        foreach ($flags as &$flag) {
            foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
                $id = (int)($flag[$key] ?? 0);
                $flag[$key . '_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null;
            }
        }
        unset($flag);

        // Pass flags and formatted grades to the view
        return view('flags/flags_management', [
            'flags' => $flags,
            'grades' => $grades // Now grades include both id and class_section_name
        ]);
    }

    public function history()
    {
        $flagModel = new FlagModel();

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

        $builder = $flagModel->orderBy('flag_datetime', 'DESC');
        if ($schoolYear !== '') {
            $builder->where('school_year', $schoolYear);
        }
        if ($semester !== '') {
            $builder->where('semester', $semester);
        }

        return $this->response->setJSON([
            'flags' => $builder->findAll(),
        ]);
    }

    public function processedFlags()
    {
        $flagModel = new FlagModel();
        $classSectionModel = new ClassSectionModel();

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

        $builder = $flagModel->orderBy('flag_datetime', 'DESC');
        if ($schoolYear !== '') {
            $builder->where('school_year', $schoolYear);
        }
        if ($semester !== '') {
            $builder->where('semester', $semester);
        }

        $flags = $builder->findAll();

        $gradeIds = [];
        foreach ($flags as $flag) {
            $gradeValue = $flag['grade'] ?? '';
            if (is_numeric($gradeValue)) {
                $gradeIds[(int)$gradeValue] = true;
            }
        }

        $gradeMap = [];
        if (!empty($gradeIds)) {
            $rows = $classSectionModel
                ->select('class_section_id, class_section_name')
                ->whereIn('class_section_id', array_keys($gradeIds))
                ->findAll();

            foreach ($rows as $row) {
                $gradeMap[(int)$row['class_section_id']] = (string)($row['class_section_name'] ?? '');
            }
        }

        // Map updater user IDs to display names for the view
        $updaterIds = [];
        foreach ($flags as $flag) {
            foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
                if (!empty($flag[$key])) {
                    $updaterIds[(int)$flag[$key]] = true;
                }
            }
        }

        $updaterMap = [];
        if (!empty($updaterIds)) {
            $rows = $this->db->table('users')
                ->select('id, firstname, lastname')
                ->whereIn('id', array_keys($updaterIds))
                ->get()
                ->getResultArray();

            foreach ($rows as $row) {
                $name = trim((string)($row['firstname'] ?? '') . ' ' . (string)($row['lastname'] ?? ''));
                $updaterMap[(int)$row['id']] = $name !== '' ? $name : ('User #' . $row['id']);
            }
        }

        foreach ($flags as &$flag) {
            foreach (['updated_by_open', 'updated_by_closed', 'updated_by_canceled'] as $key) {
                $id = (int)($flag[$key] ?? 0);
                $flag[$key . '_name'] = $id > 0 ? ($updaterMap[$id] ?? null) : null;
            }

            $gradeValue = $flag['grade'] ?? '';
            if (is_numeric($gradeValue)) {
                $flag['grade'] = $gradeMap[(int)$gradeValue] ?? (string)$gradeValue;
            }
        }
        unset($flag);

        return view('flags/processed_flags', [
            'flags' => $flags
        ]);
    }

    public function incidentAnalysis()
    {
        $flagModel = new FlagModel();
        $classSectionModel = new ClassSectionModel();

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

        $builder = $flagModel->orderBy('flag_datetime', 'DESC');
        if ($schoolYear !== '') {
            $builder->where('school_year', $schoolYear);
        }
        if ($semester !== '') {
            $builder->where('semester', $semester);
        }

        $flags = $builder->findAll();

        $gradeIds = [];
        foreach ($flags as $flag) {
            $gradeValue = $flag['grade'] ?? '';
            if (is_numeric($gradeValue)) {
                $gradeIds[(int)$gradeValue] = true;
            }
        }

        $gradeMap = [];
        if (!empty($gradeIds)) {
            $rows = $classSectionModel
                ->select('class_section_id, class_section_name')
                ->whereIn('class_section_id', array_keys($gradeIds))
                ->findAll();

            foreach ($rows as $row) {
                $gradeMap[(int)$row['class_section_id']] = (string)($row['class_section_name'] ?? '');
            }
        }

        $students = [];
        foreach ($flags as $flag) {
            $studentId = (string)($flag['student_id'] ?? '');
            $studentName = (string)($flag['student_name'] ?? '');
            $studentKey = $studentId !== '' ? 'id:' . $studentId : 'name:' . strtolower(trim($studentName));
            $gradeValue = $flag['grade'] ?? '';
            $gradeLabel = $gradeValue;
            if (is_numeric($gradeValue)) {
                $gradeLabel = $gradeMap[(int)$gradeValue] ?? (string)$gradeValue;
            }

            if (!isset($students[$studentKey])) {
                $students[$studentKey] = [
                    'student_id' => $studentId,
                    'student_name' => $studentName,
                    'grade' => (string)$gradeLabel,
                    'total' => 0,
                    'open' => 0,
                    'closed' => 0,
                    'canceled' => 0,
                    'last_incident' => null,
                    'logs' => [],
                ];
            }

            $students[$studentKey]['total'] += 1;

            $state = (string)($flag['flag_state'] ?? '');
            if ($state === 'Open') {
                $students[$studentKey]['open'] += 1;
            } elseif ($state === 'Closed') {
                $students[$studentKey]['closed'] += 1;
            } elseif ($state === 'Canceled') {
                $students[$studentKey]['canceled'] += 1;
            }

            if ($students[$studentKey]['last_incident'] === null) {
                $students[$studentKey]['last_incident'] = $flag['flag_datetime'] ?? null;
            }

            $students[$studentKey]['logs'][] = [
                'flag' => $flag['flag'] ?? '',
                'flag_state' => $state,
                'flag_datetime' => $flag['flag_datetime'] ?? null,
                'open_description' => $flag['open_description'] ?? null,
                'close_description' => $flag['close_description'] ?? null,
                'cancel_description' => $flag['cancel_description'] ?? null,
                'action_taken' => $flag['action_taken'] ?? null,
            ];
        }

        $studentRows = array_values($students);
        usort($studentRows, function ($a, $b) {
            if ($a['total'] === $b['total']) {
                return strcasecmp($a['student_name'], $b['student_name']);
            }
            return $b['total'] <=> $a['total'];
        });

        return view('flags/incident_analysis', [
            'students' => $studentRows,
            'schoolYear' => $schoolYear,
            'semester' => $semester,
        ]);
    }

    public function getStudentsByGrade($gradeId)
    {
        $studentClassModel = new StudentClassModel(); // Model for the student_class table
        $studentModel = new StudentModel();           // Model for the students table

        // Fetch student IDs for the selected grade
        $studentIds = $studentClassModel
            ->active()
            ->where('student_class.class_section_id', $gradeId)
            ->findColumn('student_id');

        // If no student IDs are found, return an empty JSON array
        if (empty($studentIds)) {
            return $this->response->setJSON([]);
        }

        // Fetch student details from students table using the retrieved IDs
        $students = $studentModel
            ->whereIn('id', $studentIds)
            ->where('is_active', 1)
            ->findAll();

        // Prepare data for JSON response with both ID and full name
        $studentData = [];
        foreach ($students as $student) {
            $studentData[] = [
                'id' => $student['id'], // Student ID
                'name' => $student['firstname'] . ' ' . $student['lastname'] // Full name
            ];
        }

        // Return JSON response with student ID and full name
        return $this->response->setJSON($studentData);
    }

    public function addFlag()
    {
        $currentFlagModel = new CurrentFlagModel();
        $studentModel = new StudentModel();
        $configModel = new ConfigurationModel();

        // Get the data from the form submission
        $studentId = $this->request->getPost('student');
        $flagType = $this->request->getPost('flag');
        $description = $this->request->getPost('description');
        $flagState = $this->request->getPost('flag_state');
        $stateDescription = $this->request->getPost('state_description'); // Additional description for "Closed" or "Canceled"

        // Retrieve student information from the database
        $student = $studentModel->find($studentId);
        if (!$student) {
            session()->setFlashdata('error', 'Student not found.');
            return $this->index();
        }

        // Get the user_id from the session for updated_by
        $userId = session()->get('user_id');

        // Get the semester and school year from configuration
        $semester = $configModel->getConfig('semester');
        $schoolYear = $configModel->getConfig('school_year');

        // Set the current system date and time for flag_datetime
        $currentDateTime = utc_now();

        // Check if a flag of the same type already exists for this student
        $existingFlag = $currentFlagModel->where('student_id', $studentId)
            ->where('flag', $flagType)
            ->first();

        if ($existingFlag) {
            // If the flag exists, update it based on the new state and description
            $data = [
                'flag_datetime'    => $currentDateTime,
                'updated_by_open'  => $userId
            ];

            // Append the new description to the appropriate field based on flag state
            if ($flagState === 'Closed') {
                $data['flag_state'] = 'Closed';
                $data['close_description'] = ($existingFlag['close_description'] ?? '') . PHP_EOL . $stateDescription;
            } elseif ($flagState === 'Canceled') {
                $data['flag_state'] = 'Canceled';
                $data['cancel_description'] = ($existingFlag['cancel_description'] ?? '') . PHP_EOL . $stateDescription;
            } else {
                $data['open_description'] = $existingFlag['open_description'] . PHP_EOL . $description;
            }

            // Update the existing flag
            $currentFlagModel->update($existingFlag['id'], $data);
            session()->setFlashdata('success', 'Flag updated successfully!');
        } else {
            // If no existing flag is found, prepare the data for insertion
            $data = [
                'student_id'        => $student['id'],
                'student_name'      => $student['firstname'] . ' ' . $student['lastname'],
                'grade'             => $this->request->getPost('grade'),
                'flag'              => $flagType,
                'flag_datetime'     => $currentDateTime,
                'flag_state'        => 'Open', // Set initial state to 'Open'
                'updated_by_open'   => $userId,
                'open_description'  => $description,
                'semester'          => $semester,
                'school_year'       => $schoolYear
            ];

            // Insert the new flag
            if ($currentFlagModel->insert($data)) {
                session()->setFlashdata('success', 'New incident added successfully!');
            } else {
                session()->setFlashdata('error', 'Failed to add new incident.');
            }
        }
        // Redirect to the list view
        return $this->index();
    }

    public function updateState($id)
    {
        log_message('debug', 'updateState method called for ID: ' . $id);
        log_message('debug', 'Flag state: ' . $this->request->getPost('flag_state'));

        $currentFlagModel = new CurrentFlagModel();
        $userId = session()->get('user_id');

        // Get the new flag state from the form
        $newState = $this->request->getPost('flag_state');
        $stateDescription = (string) ($this->request->getPost('state_description') ?? '');
        $actionTaken = (string) ($this->request->getPost('action_taken') ?? '');

        if (!$newState) {
            session()->setFlashdata('error', 'incident state not provided.');
            return $this->index();
        }

        $update = ['flag_state' => $newState];
        if ($newState === 'Closed') {
            $update['updated_by_closed'] = $userId;
            if ($stateDescription !== '') {
                $update['close_description'] = $stateDescription;
            }
            if ($actionTaken !== '') {
                $update['action_taken'] = $actionTaken;
            }
        } elseif ($newState === 'Canceled') {
            $update['updated_by_canceled'] = $userId;
            if ($stateDescription !== '') {
                $update['cancel_description'] = $stateDescription;
            }
            if ($actionTaken !== '') {
                $update['action_taken'] = $actionTaken;
            }
        }

        // Update the flag state in the database
        if ($currentFlagModel->update($id, $update)) {
            if ($newState === 'Closed' || $newState === 'Canceled') {
                $flagData = $currentFlagModel->find($id);
                if ($flagData) {
                    return $this->moveToHistory($flagData);
                }
            }
            session()->setFlashdata('success', 'Incident state updated successfully!');
        } else {
            $errors = $currentFlagModel->errors();
            log_message('error', 'Failed to update incident state: ' . print_r($errors, true));
            session()->setFlashdata('error', 'Failed to update incident state.');
        }

        // Redirect back to the flags list
        return $this->index();
    }

    public function closeFlag($flagId)
    {
        // Log the whole session array
        log_message('debug', json_encode(session()->get()));
        $currentFlagModel = new CurrentFlagModel();
        $userId = session()->get('user_id');

        // Get the current flag data
        $flagData = $currentFlagModel->find($flagId);

        // Log and check if flag data is found
        if (!$flagData) {
            log_message('error', "incident with ID {$flagId} not found in database.");
            session()->setFlashdata('error', 'Incident not found.');
            return redirect()->back();
        }

        // Proceed only if flag is not closed
        if ($flagData['flag_state'] !== 'Closed') {
            // Retrieve 'close_description' from POST request
            $closeDescription = $this->request->getPost('state_description');
            $actionTaken = $this->request->getPost('action_taken');

            // Debugging: Check if the close description is received
            if (empty($closeDescription)) {
                session()->setFlashdata('error', 'Close description is missing.');
                return redirect()->back();
            }

            // Update the flag state to Closed
            $currentFlagModel->update($flagId, [
                'flag_state' => 'Closed',
                'updated_by_closed' => $userId,
                'close_description' => $closeDescription, // Use dynamic description from form
                'action_taken' => $actionTaken
            ]);

            $flagData = $currentFlagModel->find($flagId);
            return $this->moveToHistory($flagData);
        } else {
            session()->setFlashdata('error', 'Incident is already closed.');
        }
        return $this->index();
    }

    public function cancelFlag($flagId)
    {
        $currentFlagModel = new CurrentFlagModel();
        $userId = session()->get('user_id');

        // Retrieve 'cancel_description' from POST request
        $cancelDescription = $this->request->getPost('state_description');
        $actionTaken = $this->request->getPost('action_taken');

        // Get the current flag data
        $flagData = $currentFlagModel->find($flagId);

        // Check if flag data is found
        if (!$flagData) {
            log_message('error', "Incident with ID {$flagId} not found in database.");
            session()->setFlashdata('error', 'Incident not found.');
            return redirect()->back();
        }

        // Check if the flag is not already canceled
        if ($flagData['flag_state'] !== 'Canceled') {
            // Update the flag state to Canceled
            $currentFlagModel->update($flagId, [
                'flag_state' => 'Canceled',
                'updated_by_canceled' => $userId,
                'cancel_description' => $cancelDescription,
                'action_taken' => $actionTaken
            ]);

            // Retrieve updated flag data to ensure latest state
            $flagData = $currentFlagModel->find($flagId);
            return $this->moveToHistory($flagData);
        } else {
            session()->setFlashdata('error', 'Incident is already canceled.');
        }

        return $this->index();
    }


    private function moveToHistory($flagData)
    {
        $flagModel = new FlagModel();

        // Prepare data for the flag table
        $dataToInsert = [
            'student_id'            => $flagData['student_id'],
            'student_name'          => $flagData['student_name'],
            'grade'                 => $flagData['grade'],
            'flag'                  => $flagData['flag'],
            'flag_datetime'         => $flagData['flag_datetime'],
            'flag_state'            => $flagData['flag_state'],
            'updated_by_open'       => $flagData['updated_by_open'],
            'open_description'      => $flagData['open_description'],
            'updated_by_closed'     => $flagData['updated_by_closed'],
            'close_description'     => $flagData['close_description'],
            'action_taken'          => $flagData['action_taken'],
            'updated_by_canceled'   => $flagData['updated_by_canceled'],
            'cancel_description'    => $flagData['cancel_description'],
            'semester'              => $flagData['semester'],
            'school_year'           => $flagData['school_year'],
            'created_at'            => $flagData['created_at'],
            'updated_at'            => $flagData['updated_at']
        ];

        // Insert data into the flag table
        if ($flagModel->insert($dataToInsert)) {
            // Delete the entry from the current_flag table
            $currentFlagModel = new CurrentFlagModel();
            $currentFlagModel->delete($flagData['id']);
            session()->setFlashdata('success', 'Incident has been moved to history.');
        } else {
            session()->setFlashdata('error', 'Failed to move incident to history.');
        }

        return $this->index();
    }
}
