<?php

namespace App\Controllers;

use App\Exceptions\SchoolYear\SchoolYearWriteConflictException;
use App\Models\ConfigurationModel;
use App\Models\ReportCardAcknowledgementModel;
use App\Models\StudentModel;
use CodeIgniter\Exceptions\PageNotFoundException;
use CodeIgniter\Database\BaseConnection;

class ParentReportCardController extends BaseController
{
    protected ConfigurationModel $configModel;
    protected ReportCardAcknowledgementModel $ackModel;
    protected StudentModel $studentModel;
    protected BaseConnection $db;

    public function __construct()
    {
        helper(['url', 'form']);
        $this->db = \Config\Database::connect();
        $this->configModel = new ConfigurationModel();
        $this->ackModel = new ReportCardAcknowledgementModel();
        $this->studentModel = new StudentModel();
    }

    public function index()
    {
        $parentId = $this->resolvePrimaryParentId();
        if (! $parentId) {
            return redirect()->back()->with('error', 'Unable to retrieve student data. Please contact support.');
        }

        $schoolYearContext = $this->resolveSchoolYearContext();
        $schoolYear = trim($schoolYearContext->yearName());
        $semester = trim((string) ($this->request->getGet('semester') ?? $this->configModel->getConfig('semester') ?? ''));

        $builder = $this->db->table('students s')
            ->select('s.id, s.firstname, s.lastname, cs.class_section_name')
            ->join('student_class sc', 'sc.student_id = s.id', 'left')
            ->join('classSection cs', 'cs.class_section_id = sc.class_section_id', 'left')
            ->where('s.parent_id', $parentId)
            ->orderBy('s.firstname', 'ASC')
            ->orderBy('s.lastname', 'ASC');

        if ($schoolYear !== '') {
            $builder->where('sc.school_year', $schoolYear);
        }

        $students = $builder->get()->getResultArray();
        $studentIds = array_values(array_filter(array_map(static fn ($s) => (int) ($s['id'] ?? 0), $students)));

        $ackMap = [];
        if (! empty($studentIds)) {
            $rows = $this->ackModel
                ->where('parent_id', $parentId)
                ->where('school_year', $schoolYear)
                ->where('semester', $semester)
                ->whereIn('student_id', $studentIds)
                ->findAll();
            foreach ($rows as $row) {
                $ackMap[(int) $row['student_id']] = $row;
            }
        }

        return view('parent/report_cards', [
            'students' => $students,
            'ackMap' => $ackMap,
            'schoolYear' => $schoolYear,
            'semester' => $semester,
            'isEditable' => ! $schoolYearContext->isReadonly(),
        ]);
    }

    public function view($studentId)
    {
        $parentId = $this->resolvePrimaryParentId();
        if (! $parentId) {
            return redirect()->back()->with('error', 'Unable to retrieve student data. Please contact support.');
        }

        $student = $this->studentModel->find((int) $studentId);
        if (! $student || (int) ($student['parent_id'] ?? 0) !== $parentId) {
            throw new PageNotFoundException('Student not found.');
        }

        $schoolYearContext = $this->resolveSchoolYearContext();
        $schoolYear = trim($schoolYearContext->yearName());
        $semester = trim((string) ($this->request->getGet('semester') ?? $this->configModel->getConfig('semester') ?? ''));

        if (! $schoolYearContext->isReadonly()) {
            $this->touchAcknowledgement($parentId, (int) $studentId, $schoolYear, $semester, [
                'viewed_at' => date('Y-m-d H:i:s'),
            ]);
        }

        $url = site_url('report-card/student/' . (int) $studentId);
        $query = [];
        if ($schoolYear !== '') {
            $query['school_year'] = $schoolYear;
        }
        if ($semester !== '') {
            $query['semester'] = $semester;
        }
        if ($query) {
            $url .= '?' . http_build_query($query);
        }

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

    public function sign($studentId)
    {
        $parentId = $this->resolvePrimaryParentId();
        if (! $parentId) {
            return redirect()->back()->with('error', 'Unable to retrieve student data. Please contact support.');
        }

        $schoolYearContext = $this->resolveSchoolYearContext();
        try {
            $this->assertSchoolYearWritable($schoolYearContext);
        } catch (SchoolYearWriteConflictException $e) {
            return redirect()->back()->withInput()->with('error', $e->getMessage());
        }

        $student = $this->studentModel->find((int) $studentId);
        if (! $student || (int) ($student['parent_id'] ?? 0) !== $parentId) {
            throw new PageNotFoundException('Student not found.');
        }

        $name = trim((string) $this->request->getPost('signed_name'));
        if ($name === '') {
            return redirect()->back()->with('error', 'Please type your full name to sign.');
        }

        $schoolYear = trim($schoolYearContext->yearName());
        $semester = trim((string) ($this->configModel->getConfig('semester') ?? ''));
        $now = date('Y-m-d H:i:s');
        $this->touchAcknowledgement($parentId, (int) $studentId, $schoolYear, $semester, [
            'viewed_at' => $now,
            'signed_at' => $now,
            'signed_name' => $name,
            'signer_ip' => $this->request->getIPAddress(),
        ]);

        return redirect()->to(site_url('parent/report-cards'))->with('success', 'Report card acknowledged.');
    }

    protected function resolvePrimaryParentId(): ?int
    {
        $parentId = (int) (session()->get('user_id') ?? 0);
        $userType = (string) ($_SESSION['user_type'] ?? '');
        if ($userType === 'primary') {
            return $parentId ?: null;
        }
        if ($userType === 'secondary') {
            $row = $this->db->table('parents')
                ->select('parent_id')
                ->where('secondparent_user_id', $parentId)
                ->get()
                ->getRowArray();
            return $row ? (int) ($row['parent_id'] ?? 0) : null;
        }
        if ($userType === 'tertiary') {
            $row = $this->db->table('authorized_users')
                ->select('user_id as parent_id')
                ->where('authorized_user_id', $parentId)
                ->get()
                ->getRowArray();
            return $row ? (int) ($row['parent_id'] ?? 0) : null;
        }
        return $parentId ?: null;
    }

    protected function touchAcknowledgement(
        int $parentId,
        int $studentId,
        string $schoolYear,
        string $semester,
        array $values
    ): void {
        $criteria = [
            'parent_id' => $parentId,
            'student_id' => $studentId,
            'school_year' => $schoolYear,
            'semester' => $semester,
        ];
        $existing = $this->ackModel->where($criteria)->first();
        if ($existing) {
            $this->ackModel->update((int) $existing['id'], $values);
            return;
        }
        $this->ackModel->insert(array_merge($criteria, $values));
    }
}
