<?php

namespace App\Controllers\Guru;

use App\Controllers\BaseController;
use App\Models\AssessmentModel;
use App\Models\AssessmentTypeModel;
use App\Models\AssessmentClassSettingModel;
use App\Models\AssessmentScoreModel;
use App\Models\AssessmentDetailScoreModel;
use App\Models\AcademicPeriodModel;
use App\Models\SchoolSubjectModel;
use App\Models\ClassroomModel;
use App\Models\TeachingAssignmentModel;
use App\Models\TeacherModel;
use PhpOffice\PhpSpreadsheet\Spreadsheet;
use PhpOffice\PhpSpreadsheet\Writer\Xlsx;

class Assessment extends BaseController
{
    protected $assessmentModel;
    protected $assessmentTypeModel;
    protected $assessmentClassSettingModel;
    protected $assessmentScoreModel;
    protected $assessmentDetailScoreModel;
    protected $periodModel;
    protected $subjectModel;
    protected $classroomModel;
    protected $teachingAssignmentModel;
    protected $teacherModel;

    public function __construct()
    {
        $this->assessmentModel             = new AssessmentModel();
        $this->assessmentTypeModel         = new AssessmentTypeModel();
        $this->assessmentClassSettingModel = new AssessmentClassSettingModel();
        $this->assessmentScoreModel        = new AssessmentScoreModel();
        $this->assessmentDetailScoreModel  = new AssessmentDetailScoreModel();
        $this->periodModel                 = new AcademicPeriodModel();
        $this->subjectModel                = new SchoolSubjectModel();
        $this->classroomModel              = new ClassroomModel();
        $this->teachingAssignmentModel     = new TeachingAssignmentModel();
        $this->teacherModel                = new TeacherModel();
    }

    private function checkLogin()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }
        if (session()->get('user_role') !== 'guru') {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');
        }
        return null;
    }

    private function getTeacher()
    {
        return $this->teacherModel->where('user_id', session()->get('user_id'))->first();
    }

    // Ambil kelas + mapel yang diajar guru di periode ini
    private function getMyAssignments($teacherId, $periodId)
    {
        return $this->teachingAssignmentModel
            ->select('teaching_assignments.classroom_id, teaching_assignments.subject_id,
                      school_subjects.name as subject_name,
                      classrooms.name as classroom_name,
                      grades.name as grade_name, grades.order as grade_order')
            ->join('school_subjects', 'school_subjects.id = teaching_assignments.subject_id')
            ->join('classrooms', 'classrooms.id = teaching_assignments.classroom_id')
            ->join('grades', 'grades.id = classrooms.grade_id')
            ->where('teaching_assignments.teacher_id', $teacherId)
            ->where('teaching_assignments.academic_period_id', $periodId)
            ->orderBy('grades.order', 'ASC')
            ->orderBy('classrooms.name', 'ASC')
            ->findAll();
    }

    public function index()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $teacher = $this->getTeacher();
        if (!$teacher) {
            return redirect()->to('/dashboard')->with('error', 'Data guru tidak ditemukan!');
        }

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) {
            return view('guru/assessment/index', [
                'title'        => 'Asesmen',
                'activePeriod' => null,
                'tasks'        => [],
                'teacher'      => $teacher,
                'stats'        => ['total' => 0, 'done' => 0, 'pending' => 0],
            ]);
        }

        $assignments = $this->getMyAssignments($teacher['id'], $activePeriod['id']);
        $tasks = [];

        // === 1. EVENT BERSAMA (ASTS/ASAS/ASAT) dari admin ===
        $sharedEvents = $this->assessmentModel
            ->select('assessments.*, at.name as assessment_type_name, at.code as assessment_type_code')
            ->join('assessment_types at', 'at.id = assessments.assessment_type_id')
            ->where('at.code !=', 'ASH')
            ->where('assessments.is_visible', 1)
            ->where('assessments.deleted_at', null)
            ->where('assessments.academic_period_id', $activePeriod['id'])
            ->orderBy('assessments.created_at', 'DESC')
            ->findAll();

        foreach ($sharedEvents as $event) {
            $eid = $event['id'];
            foreach ($assignments as $a) {
                $sid = $a['subject_id'];
                $cid = $a['classroom_id'];

                $totalStudents = $this->assessmentScoreModel->countStudentsInClass($cid, $activePeriod['id']);
                $gradedStudents = $this->assessmentScoreModel->countGradedStudents($eid, $cid, $sid);

                $tasks[] = [
                    'assessment_id'        => $eid,
                    'assessment_name'      => $event['name'],
                    'assessment_type_code' => $event['assessment_type_code'],
                    'subject_id'           => $sid,
                    'subject_name'         => $a['subject_name'],
                    'classroom_id'         => $cid,
                    'classroom_name'       => $a['classroom_name'],
                    'grade_name'           => $a['grade_name'],
                    'total_students'       => $totalStudents,
                    'graded_students'      => $gradedStudents,
                    'progress_percent'     => $totalStudents > 0 ? round(($gradedStudents / $totalStudents) * 100) : 0,
                    'is_open'              => $event['is_open'],
                    'academic_period_id'   => $event['academic_period_id'],
                ];
            }
        }

        // === 2. ASH milik guru ini saja ===
        $ashEvents = $this->assessmentModel
            ->select('assessments.*, at.name as assessment_type_name, at.code as assessment_type_code,
                      ss.name as subject_name')
            ->join('assessment_types at', 'at.id = assessments.assessment_type_id')
            ->join('school_subjects ss', 'ss.id = assessments.subject_id', 'left')
            ->where('at.code', 'ASH')
            ->where('assessments.created_by', session()->get('user_id'))
            ->where('assessments.deleted_at', null)
            ->where('assessments.academic_period_id', $activePeriod['id'])
            ->orderBy('assessments.created_at', 'DESC')
            ->findAll();

        foreach ($ashEvents as $ash) {
            $eid = $ash['id'];
            $sid = $ash['subject_id'];

            // Ambil kelas dari assessment_class_settings
            $ashClasses = $this->assessmentClassSettingModel
                ->select('assessment_class_settings.classroom_id,
                          classrooms.name as classroom_name,
                          grades.name as grade_name')
                ->join('classrooms', 'classrooms.id = assessment_class_settings.classroom_id')
                ->join('grades', 'grades.id = classrooms.grade_id')
                ->where('assessment_id', $eid)
                ->orderBy('grades.order', 'ASC')
                ->orderBy('classrooms.name', 'ASC')
                ->findAll();

            foreach ($ashClasses as $cls) {
                $cid = $cls['classroom_id'];
                $totalStudents = $this->assessmentScoreModel->countStudentsInClass($cid, $activePeriod['id']);
                $gradedStudents = $this->assessmentScoreModel->countGradedStudents($eid, $cid, $sid);

                $tasks[] = [
                    'assessment_id'        => $eid,
                    'assessment_name'      => $ash['name'],
                    'assessment_type_code' => $ash['assessment_type_code'],
                    'subject_id'           => $sid,
                    'subject_name'         => $ash['subject_name'] ?? '-',
                    'classroom_id'         => $cid,
                    'classroom_name'       => $cls['classroom_name'],
                    'grade_name'           => $cls['grade_name'],
                    'total_students'       => $totalStudents,
                    'graded_students'      => $gradedStudents,
                    'progress_percent'     => $totalStudents > 0 ? round(($gradedStudents / $totalStudents) * 100) : 0,
                    'is_open'              => $ash['is_open'],
                    'academic_period_id'   => $ash['academic_period_id'],
                ];
            }
        }

        $totalTasks = count($tasks);
        $doneTasks = 0;
        foreach ($tasks as $task) {
            if ($task['total_students'] > 0 && $task['graded_students'] === $task['total_students']) {
                $doneTasks++;
            }
        }
        $pendingTasks = $totalTasks - $doneTasks;

        $filterEvents = [];
        $filterSubjects = [];
        $filterClasses = [];
        foreach ($tasks as $task) {
            $filterEvents[] = $task['assessment_name'];
            $filterSubjects[] = $task['subject_name'];
            $filterClasses[] = $task['grade_name'] . ' — ' . $task['classroom_name'];
        }

        $filterEvents = array_unique($filterEvents);
        $filterSubjects = array_unique($filterSubjects);
        $filterClasses = array_unique($filterClasses);

        sort($filterEvents);
        sort($filterSubjects);
        sort($filterClasses);

        return view('guru/assessment/index', [
            'title'          => 'Asesmen Saya',
            'teacher'        => $teacher,
            'activePeriod'   => $activePeriod,
            'tasks'          => $tasks,
            'filterEvents'   => $filterEvents,
            'filterSubjects' => $filterSubjects,
            'filterClasses'  => $filterClasses,
            'stats'          => [
                'total'   => $totalTasks,
                'done'    => $doneTasks,
                'pending' => $pendingTasks,
            ],
        ]);
    }

    // -------------------------------------------------------
    // Form buat ASH
    // -------------------------------------------------------
    public function createAsh()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $teacher = $this->getTeacher();
        if (!$teacher) return redirect()->to('/guru/assessment')->with('error', 'Data guru tidak ditemukan!');

        $activePeriod = $this->periodModel->getActive();
        if (!$activePeriod) return redirect()->to('/guru/assessment')->with('error', 'Belum ada periode aktif!');

        $assignments = $this->getMyAssignments($teacher['id'], $activePeriod['id']);

        $subjectClassMap = [];
        foreach ($assignments as $a) {
            $sid = $a['subject_id'];
            if (!isset($subjectClassMap[$sid])) {
                $subjectClassMap[$sid] = [
                    'subject_id'   => $sid,
                    'subject_name' => $a['subject_name'],
                    'classrooms'   => [],
                ];
            }
            $subjectClassMap[$sid]['classrooms'][] = [
                'classroom_id'   => $a['classroom_id'],
                'classroom_name' => $a['classroom_name'],
                'grade_name'     => $a['grade_name'],
            ];
        }

        return view('guru/assessment/create_ash', [
            'title'           => 'Buat Event ASH',
            'teacher'         => $teacher,
            'activePeriod'    => $activePeriod,
            'subjectClassMap' => array_values($subjectClassMap),
        ]);
    }

    // -------------------------------------------------------
    // Simpan ASH baru
    // -------------------------------------------------------
    public function storeAsh()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $teacher = $this->getTeacher();
        if (!$teacher) return redirect()->to('/guru/assessment')->with('error', 'Data guru tidak ditemukan!');

        $rules = [
            'name'               => 'required|max_length[100]',
            'academic_period_id' => 'required|integer',
            'subject_id'         => 'required|integer',
            'start_date'         => 'required|valid_date',
            'end_date'           => 'required|valid_date',
        ];

        if (!$this->validate($rules)) {
            return redirect()->back()->with('errors', $this->validator->getErrors())->withInput();
        }

        $classroomIds = $this->request->getPost('classroom_ids');
        if (empty($classroomIds)) {
            return redirect()->back()->with('error', 'Pilih minimal 1 kelas!')->withInput();
        }

        $hasPg    = $this->request->getPost('has_pg')    ? 1 : 0;
        $hasBs    = $this->request->getPost('has_bs')    ? 1 : 0;
        $hasIsian = $this->request->getPost('has_isian') ? 1 : 0;
        $hasEssay = $this->request->getPost('has_essay') ? 1 : 0;

        if (!$hasPg && !$hasBs && !$hasIsian && !$hasEssay) {
            return redirect()->back()->with('error', 'Pilih minimal 1 jenis soal!')->withInput();
        }

        $isianMode      = $this->request->getPost('isian_mode') ?? 'total';
        $isianTotalSoal = (int) ($this->request->getPost('isian_total_soal') ?? 0);
        $essayMode      = $this->request->getPost('essay_mode') ?? 'total';
        $essayTotalSoal = (int) ($this->request->getPost('essay_total_soal') ?? 0);

        $ashType = $this->assessmentTypeModel->where('code', 'ASH')->first();

        $assessmentId = $this->assessmentModel->insert([
            'assessment_type_id' => $ashType['id'],
            'name'               => $this->request->getPost('name'),
            'description'        => $this->request->getPost('description') ?? '',
            'academic_period_id' => $this->request->getPost('academic_period_id'),
            'subject_id'         => $this->request->getPost('subject_id'),
            'classroom_id'       => null,
            'grade_id'           => null,
            'teacher_id'         => $teacher['id'],
            'start_date'         => $this->request->getPost('start_date'),
            'end_date'           => $this->request->getPost('end_date'),
            'is_open'            => 1,
            'is_visible'         => 1,
            'created_by'         => session()->get('user_id'),
            'has_pg'             => $hasPg,
            'has_bs'             => $hasBs,
            'has_isian'          => $hasIsian,
            'has_essay'          => $hasEssay,
            'isian_mode'         => $hasIsian ? $isianMode : 'total',
            'isian_total_soal'   => $hasIsian ? $isianTotalSoal : 0,
            'essay_mode'         => $hasEssay ? $essayMode : 'total',
            'essay_total_soal'   => $hasEssay ? $essayTotalSoal : 0,
        ], true);

        foreach ($classroomIds as $classroomId) {
            $this->assessmentClassSettingModel->insert([
                'assessment_id' => $assessmentId,
                'classroom_id'  => $classroomId,
                'subject_id'    => $this->request->getPost('subject_id'),
                'teacher_id'    => $teacher['id'],
                'kktp'          => 75,
                'bobot_pg'      => 0,
                'bobot_bs'      => 0,
                'bobot_isian'   => 0,
                'bobot_essay'   => 0,
                'bobot_filled'  => 0,
            ]);
        }

        return redirect()->to('/guru/assessment')->with('success', 'Event ASH berhasil dibuat!');
    }

    // -------------------------------------------------------
    // KOREKSI: setting + tabel siswa
    // -------------------------------------------------------
    public function koreksi($assessmentId, $classroomId, $subjectId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $teacher = $this->getTeacher();
        if (!$teacher) return redirect()->to('/guru/assessment')->with('error', 'Data guru tidak ditemukan!');

        $assessment = $this->assessmentModel->find($assessmentId);
        if (!$assessment) return redirect()->to('/guru/assessment')->with('error', 'Asesmen tidak ditemukan!');

        $periodId = $assessment['academic_period_id'];
        $assessmentPeriod = $this->periodModel
            ->select('academic_periods.*, academic_years.name as year_name')
            ->join('academic_years', 'academic_years.id = academic_periods.academic_year_id')
            ->find($periodId);
        $isPeriodActive = is_period_active($periodId);

        $classroom    = $this->classroomModel->find($classroomId);
        $subject      = $this->subjectModel->find($subjectId);

        $setting = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);
        if (!$setting) {
            $this->assessmentClassSettingModel->insert([
                'assessment_id' => $assessmentId,
                'classroom_id'  => $classroomId,
                'subject_id'    => $subjectId,
                'teacher_id'    => $teacher['id'],
                'kktp'          => 75,
                'bobot_pg'      => 0,
                'bobot_bs'      => 0,
                'bobot_isian'   => 0,
                'bobot_essay'   => 0,
                'bobot_filled'  => 0,
            ]);
            $setting = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);
        }

        // Jika admin set bobot → otomatis push ke setting (guru tidak perlu isi manual)
        if ($assessment['bobot_by_admin'] && $setting) {
            $needPush = (
                (int)$setting['bobot_pg']    !== (int)$assessment['admin_bobot_pg']    ||
                (int)$setting['bobot_bs']    !== (int)$assessment['admin_bobot_bs']    ||
                (int)$setting['bobot_isian'] !== (int)$assessment['admin_bobot_isian'] ||
                (int)$setting['bobot_essay'] !== (int)$assessment['admin_bobot_essay']
            );
            if ($needPush) {
                $this->assessmentClassSettingModel->update($setting['id'], [
                    'bobot_pg'     => $assessment['admin_bobot_pg'],
                    'bobot_bs'     => $assessment['admin_bobot_bs'],
                    'bobot_isian'  => $assessment['admin_bobot_isian'],
                    'bobot_essay'  => $assessment['admin_bobot_essay'],
                    'bobot_filled' => 1,
                ]);
                $setting = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);
                // Recalculate semua nilai dengan bobot baru
                $this->recalculateAll($assessmentId, $classroomId, $subjectId);
            }
        }

        $students = $this->assessmentScoreModel->getStudentsWithStatus(
            $assessmentId, $classroomId, $subjectId, $periodId
        );

        // Ambil detail per nomor untuk semua siswa
        $isianDetails = [];
        $essayDetails = [];
        foreach ($students as $s) {
            if (!empty($s['score'])) {
                $scoreId = $s['score']['id'];
                if ($assessment['has_isian'] && $assessment['isian_mode'] === 'per_nomor') {
                    $details = $this->assessmentDetailScoreModel->getDetail($scoreId, 'isian');
                    // index by nomor_soal
                    $map = [];
                    foreach ($details as $d) { $map[$d['nomor_soal']] = $d['skor']; }
                    $isianDetails[$s['id']] = $map;
                }
                if ($assessment['has_essay'] && $assessment['essay_mode'] === 'per_nomor') {
                    $details = $this->assessmentDetailScoreModel->getDetail($scoreId, 'essay');
                    $map = [];
                    foreach ($details as $d) { $map[$d['nomor_soal']] = $d['skor']; }
                    $essayDetails[$s['id']] = $map;
                }
            }
        }

        $totalSoalPg = $setting['kunci_pg'] ? $this->assessmentClassSettingModel->countSoal($setting['kunci_pg']) : 0;
        $totalSoalBs = $setting['kunci_bs'] ? $this->assessmentClassSettingModel->countSoal($setting['kunci_bs']) : 0;

        return view('guru/assessment/koreksi', [
            'title'          => 'Koreksi: ' . $assessment['name'],
            'teacher'        => $teacher,
            'assessment'     => $assessment,
            'classroom'       => $classroom,
            'subject'         => $subject,
            'activePeriod'    => $assessmentPeriod,
            'isPeriodActive'  => $isPeriodActive,
            'setting'         => $setting,
            'students'        => $students,
            'isianDetails'    => $isianDetails,
            'essayDetails'    => $essayDetails,
            'totalSoalPg'     => $totalSoalPg,
            'totalSoalBs'     => $totalSoalBs,
            'bobotByAdmin'    => (bool)($assessment['bobot_by_admin'] ?? 0),
        ]);
    }

    // -------------------------------------------------------
    // Simpan setting bobot + kunci (AJAX)
    // FIX: tidak reload, return bobot_filled agar JS aktifkan tabel tanpa refresh
    // -------------------------------------------------------
    public function saveSetting($assessmentId, $classroomId, $subjectId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $assessment = $this->assessmentModel->find($assessmentId);
        if (!$assessment) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Asesmen tidak ditemukan!',
            ]);
        }
        if (!is_period_active($assessment['academic_period_id'])) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Periode akademik untuk asesmen ini telah ditutup!',
            ]);
        }

        $teacher = $this->getTeacher();

        // Jika bobot_by_admin, simpan KKTP + kunci — bobot tidak boleh diubah guru
        if ($assessment['bobot_by_admin']) {
            $kunci_pg = $this->request->getPost('kunci_pg') ?? null;
            $kunci_bs = $this->request->getPost('kunci_bs') ?? null;

            $updateData = [
                'kktp'     => (int)($this->request->getPost('kktp') ?? 75),
                'kunci_pg' => $kunci_pg,
                'kunci_bs' => $kunci_bs,
            ];

            $setting = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);
            if ($setting) {
                $this->assessmentClassSettingModel->update($setting['id'], $updateData);
            } else {
                // Buat row baru dengan bobot dari admin
                $this->assessmentClassSettingModel->insert(array_merge($updateData, [
                    'assessment_id' => $assessmentId,
                    'classroom_id'  => $classroomId,
                    'subject_id'    => $subjectId,
                    'teacher_id'    => $teacher['id'],
                    'bobot_pg'      => $assessment['admin_bobot_pg'],
                    'bobot_bs'      => $assessment['admin_bobot_bs'],
                    'bobot_isian'   => $assessment['admin_bobot_isian'],
                    'bobot_essay'   => $assessment['admin_bobot_essay'],
                    'bobot_filled'  => 1,
                ]));
            }

            $this->recalculateAll($assessmentId, $classroomId, $subjectId);

            return $this->response->setJSON([
                'success'       => true,
                'message'       => 'KKTP dan kunci jawaban berhasil disimpan!',
                'bobot_filled'  => true,
                'total_soal_pg' => $kunci_pg ? $this->assessmentClassSettingModel->countSoal($kunci_pg) : 0,
                'total_soal_bs' => $kunci_bs ? $this->assessmentClassSettingModel->countSoal($kunci_bs) : 0,
            ]);
        }

        $bobot_pg    = (int) ($this->request->getPost('bobot_pg')    ?? 0);
        $bobot_bs    = (int) ($this->request->getPost('bobot_bs')    ?? 0);
        $bobot_isian = (int) ($this->request->getPost('bobot_isian') ?? 0);
        $bobot_essay = (int) ($this->request->getPost('bobot_essay') ?? 0);
        $totalBobot  = $bobot_pg + $bobot_bs + $bobot_isian + $bobot_essay;

        if ($totalBobot !== 100) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Total bobot harus 100% (saat ini: ' . $totalBobot . '%)',
            ]);
        }

        $kunci_pg = $this->request->getPost('kunci_pg') ?? null;
        $kunci_bs = $this->request->getPost('kunci_bs') ?? null;

        $this->assessmentClassSettingModel->saveSetting($assessmentId, $classroomId, $subjectId, [
            'teacher_id'  => $teacher['id'],
            'kktp'        => (int) ($this->request->getPost('kktp') ?? 75),
            'bobot_pg'    => $bobot_pg,
            'bobot_bs'    => $bobot_bs,
            'bobot_isian' => $bobot_isian,
            'bobot_essay' => $bobot_essay,
            'kunci_pg'    => $kunci_pg,
            'kunci_bs'    => $kunci_bs,
        ]);

        $this->recalculateAll($assessmentId, $classroomId, $subjectId);

        return $this->response->setJSON([
            'success'       => true,
            'message'       => 'Setting berhasil disimpan!',
            'bobot_filled'  => true,
            'total_soal_pg' => $kunci_pg ? $this->assessmentClassSettingModel->countSoal($kunci_pg) : 0,
            'total_soal_bs' => $kunci_bs ? $this->assessmentClassSettingModel->countSoal($kunci_bs) : 0,
        ]);
    }

    // -------------------------------------------------------
    // Simpan skor 1 siswa (AJAX)
    // FIX UTAMA: simpan score dulu → dapat ID → baru simpan detail per_nomor
    // -------------------------------------------------------
    public function saveScore()
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $assessmentId = $this->request->getPost('assessment_id');
        $classroomId  = $this->request->getPost('classroom_id');
        $subjectId    = $this->request->getPost('subject_id');
        $studentId    = $this->request->getPost('student_id');

        $assessment = $this->assessmentModel->find($assessmentId);
        if (!$assessment) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Asesmen tidak ditemukan!',
            ]);
        }
        if (!is_period_active($assessment['academic_period_id'])) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Periode akademik untuk asesmen ini telah ditutup!',
            ]);
        }

        $setting    = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);

        if (!$setting || !$setting['bobot_filled']) {
            return $this->response->setJSON([
                'success' => false,
                'message' => 'Setting bobot belum diisi atau total bobot belum 100%!',
            ]);
        }

        $scoreData = [];
        $notifPg   = null;
        $notifBs   = null;

        // --- PG ---
        $skorPg = 0;
        if ($assessment['has_pg']) {
            $jawabanPg = $this->request->getPost('jawaban_pg') ?? '';
            $scoreData['jawaban_pg'] = $jawabanPg;
            if (!empty($setting['kunci_pg'])) {
                $result  = $this->assessmentClassSettingModel->koreksiJawaban($setting['kunci_pg'], $jawabanPg);
                $skorPg  = $result['skor'];
                $notifPg = $result['notif'];
                $scoreData['notif_pg'] = $notifPg;
            }
        }
        $scoreData['skor_pg'] = $skorPg;

        // --- BS ---
        $skorBs = 0;
        if ($assessment['has_bs']) {
            $jawabanBs = $this->request->getPost('jawaban_bs') ?? '';
            $scoreData['jawaban_bs'] = $jawabanBs;
            if (!empty($setting['kunci_bs'])) {
                $result  = $this->assessmentClassSettingModel->koreksiJawaban($setting['kunci_bs'], $jawabanBs);
                $skorBs  = $result['skor'];
                $notifBs = $result['notif'];
                $scoreData['notif_bs'] = $notifBs;
            }
        }
        $scoreData['skor_bs'] = $skorBs;

        // --- ISIAN mode total ---
        $skorIsian = 0;
        if ($assessment['has_isian'] && $assessment['isian_mode'] === 'total') {
            $skorIsian = (float) ($this->request->getPost('skor_isian') ?? 0);
        }
        $scoreData['skor_isian'] = $skorIsian;

        // --- ESSAY mode total ---
        $skorEssay = 0;
        if ($assessment['has_essay'] && $assessment['essay_mode'] === 'total') {
            $skorEssay = (float) ($this->request->getPost('skor_essay') ?? 0);
        }
        $scoreData['skor_essay'] = $skorEssay;

        // Hitung nilai akhir sementara
        $nilaiAkhir = $this->assessmentClassSettingModel->hitungNilaiAkhir(
            $setting, $skorPg, $skorBs, $skorIsian, $skorEssay
        );
        $scoreData['nilai_akhir'] = $nilaiAkhir;
        $scoreData['is_complete'] = 1;

        // === SIMPAN SCORE DULU agar punya ID ===
        $this->assessmentScoreModel->saveScore($assessmentId, $studentId, $classroomId, $subjectId, $scoreData);
        $scoreRecord = $this->assessmentScoreModel->getScore($assessmentId, $studentId, $classroomId, $subjectId);

        if (!$scoreRecord) {
            return $this->response->setJSON(['success' => false, 'message' => 'Gagal menyimpan data!']);
        }

        $scoreId = $scoreRecord['id'];

        // === ISIAN PER NOMOR ===
        if ($assessment['has_isian'] && $assessment['isian_mode'] === 'per_nomor') {
            $isianDetails = $this->request->getPost('isian_details') ?? [];
            $details = [];
            foreach ($isianDetails as $nomor => $skor) {
                $details[] = ['nomor_soal' => (int) $nomor, 'skor' => (float) $skor];
            }
            $this->assessmentDetailScoreModel->saveDetails($scoreId, 'isian', $details);
            $skorIsian = $this->assessmentDetailScoreModel->hitungTotalSkor(
                $scoreId, 'isian', $assessment['isian_total_soal']
            );
            $this->assessmentScoreModel->update($scoreId, ['skor_isian' => $skorIsian]);
            $scoreData['skor_isian'] = $skorIsian;
        }

        // === ESSAY PER NOMOR ===
        if ($assessment['has_essay'] && $assessment['essay_mode'] === 'per_nomor') {
            $essayDetails = $this->request->getPost('essay_details') ?? [];
            $details = [];
            foreach ($essayDetails as $nomor => $skor) {
                $details[] = ['nomor_soal' => (int) $nomor, 'skor' => (float) $skor];
            }
            $this->assessmentDetailScoreModel->saveDetails($scoreId, 'essay', $details);
            $skorEssay = $this->assessmentDetailScoreModel->hitungTotalSkor(
                $scoreId, 'essay', $assessment['essay_total_soal']
            );
            $this->assessmentScoreModel->update($scoreId, ['skor_essay' => $skorEssay]);
            $scoreData['skor_essay'] = $skorEssay;
        }

        // === Hitung nilai akhir FINAL setelah semua skor lengkap ===
        $nilaiAkhir = $this->assessmentClassSettingModel->hitungNilaiAkhir(
            $setting,
            $scoreData['skor_pg'],
            $scoreData['skor_bs'],
            $scoreData['skor_isian'],
            $scoreData['skor_essay']
        );
        $this->assessmentScoreModel->update($scoreId, ['nilai_akhir' => $nilaiAkhir]);

        return $this->response->setJSON([
            'success'     => true,
            'nilai_akhir' => $nilaiAkhir,
            'skor_pg'     => $scoreData['skor_pg'],
            'skor_bs'     => $scoreData['skor_bs'],
            'skor_isian'  => $scoreData['skor_isian'],
            'skor_essay'  => $scoreData['skor_essay'],
            'notif_pg'    => $notifPg,
            'notif_bs'    => $notifBs,
        ]);
    }

    // -------------------------------------------------------
    // Recalculate nilai akhir semua siswa setelah bobot berubah
    // -------------------------------------------------------
    private function recalculateAll($assessmentId, $classroomId, $subjectId)
    {
        $setting = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);
        if (!$setting || !$setting['bobot_filled']) return;

        $scores = $this->assessmentScoreModel
            ->where('assessment_id', $assessmentId)
            ->where('classroom_id', $classroomId)
            ->where('subject_id', $subjectId)
            ->findAll();

        foreach ($scores as $score) {
            $nilaiAkhir = $this->assessmentClassSettingModel->hitungNilaiAkhir(
                $setting,
                $score['skor_pg']    ?? 0,
                $score['skor_bs']    ?? 0,
                $score['skor_isian'] ?? 0,
                $score['skor_essay'] ?? 0,
            );
            $this->assessmentScoreModel->update($score['id'], ['nilai_akhir' => $nilaiAkhir]);
        }
    }

    public function export($assessmentId, $classroomId, $subjectId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;

        $assessment   = $this->assessmentModel->find($assessmentId);
        if (!$assessment) return redirect()->to('/guru/assessment')->with('error', 'Asesmen tidak ditemukan!');
        $classroom    = $this->classroomModel->find($classroomId);
        $periodId     = $assessment['academic_period_id'];
        $activePeriod = $this->periodModel
            ->select('academic_periods.*, academic_years.name as year_name')
            ->join('academic_years', 'academic_years.id = academic_periods.academic_year_id')
            ->find($periodId);
        $setting      = $this->assessmentClassSettingModel->getSetting($assessmentId, $classroomId, $subjectId);

        $db         = \Config\Database::connect();
        $school     = $db->table('school_settings')->get()->getRowArray();
        $schoolName = $school['school_name'] ?? 'Nama Sekolah';

        // FIX: Ambil mapel dari subjectId
        $subject     = $this->subjectModel->find($subjectId);
        $subjectName = $subject['name'] ?? '-';
        $subjectCode = $subject['code'] ?? 'MAPEL';

        $students = $this->assessmentScoreModel->getStudentsWithStatus(
            $assessmentId, $classroomId, $subjectId, $periodId
        );

        $className   = $classroom['name'] ?? '-';
        $periodLabel = 'Semester ' . ($activePeriod['semester'] ?? '') . ' — ' . ($activePeriod['year_name'] ?? '');
        $kktp        = $setting['kktp'] ?? 75;
        $totalSiswa  = count($students);

        $jumlahTuntas = 0;
        foreach ($students as $s) {
            $na = $s['score']['nilai_akhir'] ?? null;
            if ($na !== null) {
                $na = round($na, 2);
                if ($na >= $kktp) {
                    $jumlahTuntas++;
                }
            }
        }

        // ── Warna tema ────────────────────────────────────────────
        $clrNavy    = '1B2A4A';   // header utama
        $clrAccent  = '2563EB';   // accent biru
        $clrSubHdr  = '1E3A5F';   // sub-header
        $clrLabelBg = 'EFF6FF';   // background label info
        $clrAltRow  = 'F0F4FF';   // alternating row
        $clrTuntas  = '14532D';   // font tuntas
        $clrTuntasBg= 'DCFCE7';
        $clrBelum   = '7F1D1D';
        $clrBelumBg = 'FEE2E2';
        $clrBorder  = 'CBD5E1';

        // ── Spreadsheet ───────────────────────────────────────────
        $spreadsheet = new Spreadsheet();
        $sheet = $spreadsheet->getActiveSheet();
        $sheet->setTitle('Nilai ' . $subjectCode);

        // ── Style helpers ─────────────────────────────────────────
        $styleSchool = [
            'font'      => ['bold' => true, 'size' => 14, 'color' => ['rgb' => 'FFFFFF']],
            'fill'      => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => $clrNavy]],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
                            'vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER],
        ];
        $styleEventTitle = [
            'font'      => ['bold' => true, 'size' => 11, 'color' => ['rgb' => 'FFFFFF']],
            'fill'      => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => $clrSubHdr]],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
                            'vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER],
        ];
        $styleLabel = [
            'font'      => ['bold' => true, 'size' => 10, 'color' => ['rgb' => $clrNavy]],
            'fill'      => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => $clrLabelBg]],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT,
                            'vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
                            'indent'     => 1],
            'borders'   => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                                            'color'       => ['rgb' => $clrBorder]]],
        ];
        $styleValue = [
            'font'      => ['size' => 10],
            'fill'      => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => 'FFFFFF']],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT,
                            'vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
                            'indent'     => 1],
            'borders'   => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                                            'color'       => ['rgb' => $clrBorder]]],
        ];
        $styleTableHeader = [
            'font'      => ['bold' => true, 'size' => 10, 'color' => ['rgb' => 'FFFFFF']],
            'fill'      => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => $clrAccent]],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER,
                            'vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
                            'wrapText'   => true],
            'borders'   => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                                            'color'       => ['rgb' => 'FFFFFF']]],
        ];
        $styleDataBorder = [
            'borders'   => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                                            'color'       => ['rgb' => $clrBorder]]],
            'alignment' => ['vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER],
            'font'      => ['size' => 10],
        ];
        $styleTuntas = [
            'font' => ['bold' => true, 'color' => ['rgb' => $clrTuntas]],
            'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                    'startColor' => ['rgb' => $clrTuntasBg]],
        ];
        $styleBelum = [
            'font' => ['bold' => true, 'color' => ['rgb' => $clrBelum]],
            'fill' => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                    'startColor' => ['rgb' => $clrBelumBg]],
        ];
        $styleSummaryLabel = [
            'font'      => ['bold' => true, 'size' => 10, 'color' => ['rgb' => $clrNavy]],
            'fill'      => ['fillType' => \PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID,
                            'startColor' => ['rgb' => $clrLabelBg]],
            'alignment' => ['horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT,
                            'vertical'   => \PhpOffice\PhpSpreadsheet\Style\Alignment::VERTICAL_CENTER,
                            'indent'     => 1],
            'borders'   => ['allBorders' => ['borderStyle' => \PhpOffice\PhpSpreadsheet\Style\Border::BORDER_THIN,
                                            'color'       => ['rgb' => $clrBorder]]],
        ];

        // ── Baris 1: Nama Sekolah ─────────────────────────────────
        $sheet->mergeCells('A1:F1');
        $sheet->setCellValue('A1', strtoupper($schoolName));
        $sheet->getStyle('A1')->applyFromArray($styleSchool);
        $sheet->getRowDimension(1)->setRowHeight(26);

        // ── Baris 2: Judul Event ──────────────────────────────────
        $sheet->mergeCells('A2:F2');
        $sheet->setCellValue('A2', 'DAFTAR NILAI ' . strtoupper($assessment['name']) . ' — ' . strtoupper($subjectName) . ' — KELAS ' . strtoupper($className));
        $sheet->getStyle('A2')->applyFromArray($styleEventTitle);
        $sheet->getRowDimension(2)->setRowHeight(20);

        // ── Baris 3: spacer ───────────────────────────────────────
        $sheet->getRowDimension(3)->setRowHeight(4);

        // ── Baris 4-7: Info — [A-B] Label | [C-F] Value ──────────
        $infos = [
            4 => ['Asesmen',        $assessment['name']],
            5 => ['Kelas',          $className],
            6 => ['Mata Pelajaran', $subjectName],
            7 => ['Periode',        $periodLabel],
        ];
        foreach ($infos as $r => [$lbl, $val]) {
            $sheet->mergeCells('A' . $r . ':B' . $r);
            $sheet->setCellValue('A' . $r, $lbl);
            $sheet->getStyle('A' . $r . ':B' . $r)->applyFromArray($styleLabel);

            $sheet->mergeCells('C' . $r . ':F' . $r);
            $sheet->setCellValue('C' . $r, $val);
            $sheet->getStyle('C' . $r . ':F' . $r)->applyFromArray($styleValue);

            $sheet->getRowDimension($r)->setRowHeight(17);
        }

        // ── Baris 8: spacer ───────────────────────────────────────
        $sheet->getRowDimension(8)->setRowHeight(4);

        // ── Baris 9: Header tabel — A-F ───────────────────────────
        // A=No, B=NIS, C=NISN, D=Nama Siswa, E=Nilai, F=Keterangan
        $headers = ['No', 'NIS', 'NISN', 'Nama Siswa', 'Nilai', 'Keterangan'];
        $hCols   = ['A','B','C','D','E','F'];
        foreach ($headers as $i => $h) {
            $sheet->setCellValue($hCols[$i] . '9', $h);
        }
        $sheet->getStyle('A9:F9')->applyFromArray($styleTableHeader);
        $sheet->getRowDimension(9)->setRowHeight(20);

        // ── Data siswa mulai baris 10 ─────────────────────────────
        $no  = 1;
        $row = 10;
        foreach ($students as $s) {
            $nilaiAkhir  = $s['score']['nilai_akhir'] ?? null;
            if ($nilaiAkhir !== null) {
                $nilaiAkhir = round($nilaiAkhir, 2);
                $tercapai   = ($nilaiAkhir >= $kktp);
                $ket        = $tercapai ? 'Tercapai' : 'Belum Tercapai';
            } else {
                $tercapai   = false;
                $ket        = '-';
            }

            $sheet->setCellValue('A' . $row, $no);
            $sheet->setCellValue('B' . $row, $s['nis'] ?? '-');
            $sheet->setCellValue('C' . $row, $s['nisn'] ?? '');
            $sheet->setCellValue('D' . $row, $s['full_name']);

            if ($nilaiAkhir !== null) {
                $sheet->setCellValue('E' . $row, $nilaiAkhir);
                $sheet->getStyle('E' . $row)->getNumberFormat()->setFormatCode('0.00');
            } else {
                $sheet->setCellValue('E' . $row, '-');
            }

            $sheet->setCellValue('F' . $row, $ket);

            // Style baris dasar
            $sheet->getStyle('A' . $row . ':F' . $row)->applyFromArray($styleDataBorder);

            // Rata tengah: No, NIS, NISN, Nilai, Keterangan
            foreach (['A','B','C','E','F'] as $col) {
                $sheet->getStyle($col . $row)->getAlignment()
                    ->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
            }

            // Nama: shrink to fit
            $sheet->getStyle('D' . $row)->getAlignment()
                ->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_LEFT);
            $sheet->getStyle('D' . $row)->getAlignment()->setShrinkToFit(true);

            // Alternating row (kolom A-D saja, biar nilai & ket punya warna sendiri)
            if ($no % 2 === 0) {
                $sheet->getStyle('A' . $row . ':D' . $row)->getFill()
                    ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
                    ->getStartColor()->setRGB($clrAltRow);
            }

            // Warna nilai & keterangan
            if ($nilaiAkhir !== null) {
                $sheet->getStyle('E' . $row)->getFont()->getColor()
                    ->setRGB($tercapai ? $clrTuntas : $clrBelum);
                $sheet->getStyle('E' . $row)->getFill()
                    ->setFillType(\PhpOffice\PhpSpreadsheet\Style\Fill::FILL_SOLID)
                    ->getStartColor()->setRGB($tercapai ? $clrTuntasBg : $clrBelumBg);
                $sheet->getStyle('F' . $row)->applyFromArray($tercapai ? $styleTuntas : $styleBelum);
            }

            $sheet->getRowDimension($row)->setRowHeight(15);
            $no++;
            $row++;
        }

        // ── Spacer setelah data ───────────────────────────────────
        $sheet->getRowDimension($row)->setRowHeight(6);
        $row++;

        // ── Ringkasan ─────────────────────────────────────────────
        $summaries = [
            ['Total Siswa',                      $totalSiswa,                  null],
            ['Tercapai (≥ KKTP ' . $kktp . ')', $jumlahTuntas,                $styleTuntas],
            ['Belum Tercapai',                   $totalSiswa - $jumlahTuntas,  $styleBelum],
        ];
        foreach ($summaries as [$lbl, $val, $valStyle]) {
            $sheet->mergeCells('A' . $row . ':D' . $row);
            $sheet->setCellValue('A' . $row, $lbl);
            $sheet->getStyle('A' . $row . ':D' . $row)->applyFromArray($styleSummaryLabel);

            $sheet->mergeCells('E' . $row . ':F' . $row);
            $sheet->setCellValue('E' . $row, $val);
            $sheet->getStyle('E' . $row . ':F' . $row)->applyFromArray($styleValue);
            if ($valStyle) {
                $sheet->getStyle('E' . $row . ':F' . $row)->applyFromArray($valStyle);
            }
            $sheet->getStyle('E' . $row)->getAlignment()
                ->setHorizontal(\PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER);
            $sheet->getRowDimension($row)->setRowHeight(17);
            $row++;
        }

        // ── Lebar kolom ───────────────────────────────────────────
        $sheet->getColumnDimension('A')->setWidth(5);    // No
        $sheet->getColumnDimension('B')->setWidth(14);   // NIS
        $sheet->getColumnDimension('C')->setWidth(14);   // NISN
        $sheet->getColumnDimension('D')->setWidth(36);   // Nama
        $sheet->getColumnDimension('E')->setWidth(10);   // Nilai
        $sheet->getColumnDimension('F')->setWidth(17);   // Keterangan

        // Sembunyikan kolom G dst
        for ($c = ord('G'); $c <= ord('Z'); $c++) {
            $sheet->getColumnDimension(chr($c))->setVisible(false);
        }

        // Freeze pane di baris data
        $sheet->freezePane('A10');

        // Print area & page setup
        $sheet->getPageSetup()
            ->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_PORTRAIT)
            ->setPaperSize(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::PAPERSIZE_A4)
            ->setFitToPage(true)
            ->setFitToWidth(1)
            ->setFitToHeight(0);
        $sheet->getPrintGridlines(false);
        $sheet->getPageMargins()->setTop(0.5)->setBottom(0.5)->setLeft(0.5)->setRight(0.5);

        // ── Filename ──────────────────────────────────────────────
        $safeCode  = preg_replace('/[^A-Za-z0-9]/', '', $subjectCode);
        $safeName  = preg_replace('/[^A-Za-z0-9]/', '_', $assessment['name']);
        $safeClass = preg_replace('/[^A-Za-z0-9]/', '', $className);
        $filename  = $safeCode . '_' . $safeName . '_' . $safeClass . '_' . date('Ymd') . '.xlsx';

        header('Content-Type: application/vnd.openxmlformats-officedocument.spreadsheetml.sheet');
        header('Content-Disposition: attachment;filename="' . $filename . '"');
        header('Cache-Control: max-age=0');

        $writer = new Xlsx($spreadsheet);
        $writer->save('php://output');
        exit;
    }
}