<?php

namespace App\Controllers\Admin;

use App\Controllers\BaseController;
use App\Models\AscImportModel;
use App\Models\AscPeriodModel;
use App\Models\AscSubjectModel;
use App\Models\AscTeacherModel;
use App\Models\AscClassModel;
use App\Models\AscScheduleModel;

class AscImport extends BaseController
{
    protected $importModel;
    protected $periodModel;
    protected $subjectModel;
    protected $teacherModel;
    protected $classModel;
    protected $scheduleModel;

    public function __construct()
    {
        $this->importModel   = new AscImportModel();
        $this->periodModel   = new AscPeriodModel();
        $this->subjectModel  = new AscSubjectModel();
        $this->teacherModel  = new AscTeacherModel();
        $this->classModel    = new AscClassModel();
        $this->scheduleModel = new AscScheduleModel();
    }

    // ── AUTH CHECK ─────────────────────────────────────────────────────────

    private function checkLogin()
    {
        if (!session()->get('logged_in')) {
            return redirect()->to('/login');
        }
        return null;
    }

    private function checkAdmin()
    {
        $role = session()->get('user_role');
        if (!in_array($role, ['superadmin', 'admin'])) {
            return redirect()->to('/dashboard')->with('error', 'Akses ditolak!');
        }
        return null;
    }

    // ── INDEX — Daftar semua import ────────────────────────────────────────

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

        $data = [
            'title'   => 'Import Jadwal aSc Timetables',
            'imports' => $this->importModel->getAll(),
            'active'  => $this->importModel->getActive(),
        ];

        return view('asc/import/index', $data);
    }

    // ── FORM UPLOAD ────────────────────────────────────────────────────────

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

        return view('asc/import/create', [
            'title' => 'Upload Jadwal XML',
        ]);
    }

    // ── PROSES UPLOAD & PARSE XML ──────────────────────────────────────────

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

        // Validasi form
        $rules = [
            'name'          => 'required|max_length[100]',
            'academic_year' => 'required|max_length[20]',
            'semester'      => 'required|in_list[Ganjil,Genap]',
            'xml_file'      => 'uploaded[xml_file]|max_size[xml_file,5120]',
        ];

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

        $file = $this->request->getFile('xml_file');

        // Validasi ekstensi manual (karena CI4 tidak punya rule ext untuk xml)
        $ext = strtolower($file->getClientExtension());
        if ($ext !== 'xml') {
            return redirect()->back()
                ->with('error', 'File harus berformat .xml!')
                ->withInput();
        }

        // Baca isi file XML
        $xmlContent = file_get_contents($file->getTempName());
        if (!$xmlContent) {
            return redirect()->back()
                ->with('error', 'Gagal membaca file XML!')
                ->withInput();
        }

        // Coba parse XML
        libxml_use_internal_errors(true);
        $xml = simplexml_load_string($xmlContent);

        if ($xml === false) {
            $errors = libxml_get_errors();
            $msg    = 'File XML tidak valid!';
            if (!empty($errors)) {
                $msg .= ' ' . $errors[0]->message;
            }
            return redirect()->back()->with('error', $msg)->withInput();
        }

        // Simpan file XML ke folder uploads
        $fileName = date('YmdHis') . '_' . $file->getClientName();
        $file->move(WRITEPATH . 'uploads/asc', $fileName);

        // Mulai transaksi database
        $db = \Config\Database::connect();
        $db->transStart();

        try {
            // 1. Simpan header import
            $importId = $this->importModel->insert([
                'name'          => $this->request->getPost('name'),
                'academic_year' => $this->request->getPost('academic_year'),
                'semester'      => $this->request->getPost('semester'),
                'filename'      => $fileName,
                'is_active'     => 0,
                'imported_by'   => session()->get('user_id'),
                'notes'         => $this->request->getPost('notes'),
            ]);

            // 2. Parse & simpan tiap bagian XML
            $this->parsePeriods($xml, $importId);
            $this->parseSubjects($xml, $importId);
            $this->parseTeachers($xml, $importId);
            $this->parseClasses($xml, $importId);

            // 3. Parse jadwal (lessons + cards) — yang paling kompleks
            $totalSchedules = $this->parseSchedules($xml, $importId);

            // 4. Update total jadwal
            $this->importModel->updateTotalSchedules($importId, $totalSchedules);

            $db->transComplete();

            if ($db->transStatus() === false) {
                throw new \Exception('Transaksi database gagal!');
            }

            return redirect()->to('/asc-import')
                ->with('success', "Import berhasil! {$totalSchedules} slot jadwal berhasil diproses.");

        } catch (\Exception $e) {
            $db->transRollback();

            // Hapus data yang sudah tersimpan jika ada error
            if (isset($importId) && $importId) {
                $this->deleteImportData($importId);
                $this->importModel->delete($importId);
            }

            return redirect()->back()
                ->with('error', 'Gagal import: ' . $e->getMessage())
                ->withInput();
        }
    }

    // ── SET AKTIF ──────────────────────────────────────────────────────────

    public function setActive($id)
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if ($redirect = $this->checkAdmin()) return $redirect;

        $import = $this->importModel->find($id);
        if (!$import) {
            return redirect()->to('/asc-import')->with('error', 'Data tidak ditemukan!');
        }

        $this->importModel->setActive($id);

        return redirect()->to('/asc-import')
            ->with('success', "Jadwal \"{$import['name']}\" sekarang aktif!");
    }

    public function setInactive($id)
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if ($redirect = $this->checkAdmin()) return $redirect;

        $import = $this->importModel->find($id);
        if (!$import) {
            return redirect()->to('/asc-import')->with('error', 'Data tidak ditemukan!');
        }

        $this->importModel->update($id, ['is_active' => 0]);

        return redirect()->to('/asc-import')
            ->with('success', "Jadwal \"{$import['name']}\" berhasil dinonaktifkan.");
    }

    // ── HAPUS IMPORT ───────────────────────────────────────────────────────

    public function delete($id)
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if ($redirect = $this->checkAdmin()) return $redirect;

        $import = $this->importModel->find($id);
        if (!$import) {
            return redirect()->to('/asc-import')->with('error', 'Data tidak ditemukan!');
        }

        // Hapus semua data terkait
        $this->deleteImportData($id);

        // Hapus file XML
        $filePath = WRITEPATH . 'uploads/asc/' . $import['filename'];
        if (file_exists($filePath)) {
            unlink($filePath);
        }

        $this->importModel->delete($id);

        return redirect()->to('/asc-import')
            ->with('success', "Import \"{$import['name']}\" berhasil dihapus!");
    }

    // ── DETAIL IMPORT (AJAX) ───────────────────────────────────────────────

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

        $import   = $this->importModel->find($id);
        $teachers = $this->teacherModel->getByImport($id);
        $classes  = $this->classModel->getByImport($id);
        $subjects = $this->subjectModel->getByImport($id);
        $periods  = $this->periodModel->getByImport($id);

        return $this->response->setJSON([
            'import'   => $import,
            'teachers' => $teachers,
            'classes'  => $classes,
            'subjects' => $subjects,
            'periods'  => $periods,
        ]);
    }

    // ══════════════════════════════════════════════════════════════════════
    // PRIVATE — PARSER METHODS
    // ══════════════════════════════════════════════════════════════════════

    // ── PARSE PERIODS ──────────────────────────────────────────────────────

    private function parsePeriods($xml, $importId)
    {
        if (!isset($xml->periods->period)) return;

        $batch = [];
        $now   = date('Y-m-d H:i:s');

        foreach ($xml->periods->period as $period) {
            $batch[] = [
                'import_id'     => $importId,
                'period_number' => (int) $period['period'],
                'name'          => (string) $period['name'],
                'start_time'    => (string) $period['starttime'],
                'end_time'      => (string) $period['endtime'],
                'created_at'    => $now,
                'updated_at'    => $now,
            ];
        }

        if (!empty($batch)) {
            $this->periodModel->insertBatch($batch);
        }
    }

    // ── PARSE SUBJECTS ─────────────────────────────────────────────────────

    private function parseSubjects($xml, $importId)
    {
        if (!isset($xml->subjects->subject)) return;

        $batch = [];
        $now   = date('Y-m-d H:i:s');

        foreach ($xml->subjects->subject as $subject) {
            $batch[] = [
                'import_id'  => $importId,
                'asc_id'     => (string) $subject['id'],
                'name'       => (string) $subject['name'],
                'short_code' => (string) $subject['short'],
                'created_at' => $now,
                'updated_at' => $now,
            ];
        }

        if (!empty($batch)) {
            $this->subjectModel->insertBatch($batch);
        }
    }

    private function hslToHex($h, $s, $l) {
        $h /= 360;
        $s /= 100;
        $l /= 100;

        $r = $l;
        $g = $l;
        $b = $l;

        $v = ($l <= 0.5) ? ($l * (1.0 + $s)) : ($l + $s - $l * $s);
        if ($v > 0) {
            $m = $l + $l - $v;
            $sv = ($v - $m) / $v;
            $h *= 6.0;
            $sextant = floor($h);
            $fract = $h - $sextant;
            $vsf = $v * $sv * $fract;
            $mid1 = $m + $vsf;
            $mid2 = $v - $vsf;

            switch ($sextant) {
                case 0: $r = $v; $g = $mid1; $b = $m; break;
                case 1: $r = $mid2; $g = $v; $b = $m; break;
                case 2: $r = $m; $g = $v; $b = $mid1; break;
                case 3: $r = $m; $g = $mid2; $b = $v; break;
                case 4: $r = $mid1; $g = $m; $b = $v; break;
                case 5: $r = $v; $g = $m; $b = $mid2; break;
            }
        }

        $r = (int)round($r * 255);
        $g = (int)round($g * 255);
        $b = (int)round($b * 255);

        return sprintf("#%02x%02x%02x", $r, $g, $b);
    }

    // ── PARSE TEACHERS ─────────────────────────────────────────────────────

    private function parseTeachers($xml, $importId)
    {
        if (!isset($xml->teachers->teacher)) return;

        $batch = [];
        $now   = date('Y-m-d H:i:s');
        $index = 0;

        foreach ($xml->teachers->teacher as $teacher) {
            $hue = ($index * 137.5) % 360;
            $sat = 70 + ($index % 3) * 15;
            $lit = 40 + (($index * 3) % 4) * 15;
            $color = $this->hslToHex($hue, $sat, $lit);
            $index++;

            $batch[] = [
                'import_id'  => $importId,
                'asc_id'     => (string) $teacher['id'],
                'name'       => (string) $teacher['name'],
                'short_code' => (string) $teacher['short'],
                'gender'     => (string) $teacher['gender'] ?: 'M',
                'color'      => $color,
                'created_at' => $now,
                'updated_at' => $now,
            ];
        }

        if (!empty($batch)) {
            $this->teacherModel->insertBatch($batch);
        }
    }

    // ── PARSE CLASSES ──────────────────────────────────────────────────────

    private function parseClasses($xml, $importId)
    {
        if (!isset($xml->classes->class)) return;

        $batch = [];
        $now   = date('Y-m-d H:i:s');

        foreach ($xml->classes->class as $class) {
            $name = (string) $class['name'];

            // Ambil grade level dari prefix nama kelas
            // Misal: "7A" → 7, "8A1" → 8, "9F" → 9
            $gradeLevel = null;
            if (preg_match('/^(\d+)/', $name, $matches)) {
                $gradeLevel = (int) $matches[1];
            }

            $batch[] = [
                'import_id'   => $importId,
                'asc_id'      => (string) $class['id'],
                'name'        => $name,
                'short_name'  => (string) $class['short'],
                'grade_level' => $gradeLevel,
                'created_at'  => $now,
                'updated_at'  => $now,
            ];
        }

        if (!empty($batch)) {
            $this->classModel->insertBatch($batch);
        }
    }

    // ── PARSE SCHEDULES (LESSONS + CARDS) ─────────────────────────────────
    // Ini yang paling kompleks:
    // - lessons   = siapa mengajar apa di kelas mana
    // - cards     = lessons tersebut dijadwalkan hari apa & jam berapa
    // Kita gabungkan keduanya menjadi satu baris flat di asc_schedules

    private function parseSchedules($xml, $importId)
    {
        if (!isset($xml->lessons->lesson) || !isset($xml->cards->card)) {
            return 0;
        }

        // ── Buat lookup dari data yang sudah tersimpan ──────────────────

        $subjectLookup = $this->subjectModel->getLookup($importId);
        $teacherLookup = $this->teacherModel->getLookup($importId);
        $classLookup   = $this->classModel->getLookup($importId);
        $periodLookup  = $this->periodModel->getLookup($importId);

        // ── Map day string → day number ────────────────────────────────
        // Format days di XML: "100000" = Senin, "010000" = Selasa, dst
        $dayMap = [
            '100000' => ['number' => 1, 'name' => 'Senin'],
            '010000' => ['number' => 2, 'name' => 'Selasa'],
            '001000' => ['number' => 3, 'name' => 'Rabu'],
            '000100' => ['number' => 4, 'name' => 'Kamis'],
            '000010' => ['number' => 5, 'name' => 'Jumat'],
            '000001' => ['number' => 6, 'name' => 'Sabtu'],
        ];

        // ── Build lesson lookup: lesson_id → lesson data ───────────────
        $lessonLookup = [];

        foreach ($xml->lessons->lesson as $lesson) {
            $lessonId = (string) $lesson['id'];

            // Ambil class id pertama (ada kelas yang punya beberapa classids)
            $classIds  = explode(',', (string) $lesson['classids']);
            $classId   = trim($classIds[0]);

            // Ambil teacher id pertama
            $teacherIds = explode(',', (string) $lesson['teacherids']);
            $teacherId  = trim($teacherIds[0]);

            $subjectId = (string) $lesson['subjectid'];

            // Resolve nama dari lookup
            $className   = $classLookup[$classId]['name']        ?? $classId;
            $gradeLevel  = $classLookup[$classId]['grade_level']  ?? null;
            $subjectName = $subjectLookup[$subjectId]['name']      ?? $subjectId;
            $subjectCode = $subjectLookup[$subjectId]['short_code'] ?? $subjectId;
            $teacherName = $teacherLookup[$teacherId]['name']       ?? $teacherId;
            $teacherCode = $teacherLookup[$teacherId]['short_code']  ?? $teacherId;
            $teacherColor = $teacherLookup[$teacherId]['color']      ?? '#CCCCCC';

            $lessonLookup[$lessonId] = [
                'class_asc_id'   => $classId,
                'class_name'     => $className,
                'grade_level'    => $gradeLevel,
                'subject_asc_id' => $subjectId,
                'subject_name'   => $subjectName,
                'subject_code'   => $subjectCode,
                'teacher_asc_id' => $teacherId,
                'teacher_name'   => $teacherName,
                'teacher_code'   => $teacherCode,
                'teacher_color'  => $teacherColor,
            ];
        }

        // ── Proses setiap card ─────────────────────────────────────────
        $batch = [];
        $now   = date('Y-m-d H:i:s');

        foreach ($xml->cards->card as $card) {
            $lessonId    = (string) $card['lessonid'];
            $periodNum   = (int)    $card['period'];
            $daysString  = (string) $card['days'];

            // Cari lesson yang sesuai
            if (!isset($lessonLookup[$lessonId])) {
                continue;
            }

            $lesson = $lessonLookup[$lessonId];

            // Resolve hari dari days string
            if (!isset($dayMap[$daysString])) {
                continue; // Skip hari yang tidak dikenal
            }

            $day = $dayMap[$daysString];

            // Resolve waktu dari period lookup
            $startTime = $periodLookup[$periodNum]['start_time'] ?? '';
            $endTime   = $periodLookup[$periodNum]['end_time']   ?? '';

            $batch[] = [
                'import_id'      => $importId,
                'class_asc_id'   => $lesson['class_asc_id'],
                'class_name'     => $lesson['class_name'],
                'grade_level'    => $lesson['grade_level'],
                'subject_asc_id' => $lesson['subject_asc_id'],
                'subject_name'   => $lesson['subject_name'],
                'subject_code'   => $lesson['subject_code'],
                'teacher_asc_id' => $lesson['teacher_asc_id'],
                'teacher_name'   => $lesson['teacher_name'],
                'teacher_code'   => $lesson['teacher_code'],
                'teacher_color'  => $lesson['teacher_color'],
                'day_number'     => $day['number'],
                'day_name'       => $day['name'],
                'period_number'  => $periodNum,
                'start_time'     => $startTime,
                'end_time'       => $endTime,
                'created_at'     => $now,
                'updated_at'     => $now,
            ];

            // Insert per 500 baris agar tidak overload memory
            if (count($batch) >= 500) {
                $this->scheduleModel->insertBatch($batch);
                $batch = [];
            }
        }

        // Insert sisa batch
        if (!empty($batch)) {
            $this->scheduleModel->insertBatch($batch);
        }

        return $this->scheduleModel->where('import_id', $importId)->countAllResults();
    }

    // ── HAPUS SEMUA DATA SATU IMPORT ───────────────────────────────────────

    private function deleteImportData($importId)
    {
        $this->scheduleModel->deleteByImport($importId);
        $this->periodModel->deleteByImport($importId);
        $this->subjectModel->deleteByImport($importId);
        $this->teacherModel->deleteByImport($importId);
        $this->classModel->deleteByImport($importId);
    }

    // ── EDIT PERIODE / JAM PELAJARAN ─────────────────────────────────────────

    public function editPeriods($importId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if ($redirect = $this->checkAdmin()) return $redirect;

        $import = $this->importModel->find($importId);
        if (!$import) {
            return redirect()->to('/asc-import')->with('error', 'Data tidak ditemukan!');
        }

        $periods = $this->periodModel->getByImport($importId);

        $data = [
            'title'   => 'Edit Jam Pelajaran - ' . $import['name'],
            'import'  => $import,
            'periods' => $periods,
        ];

        return view('asc/import/edit_periods', $data);
    }

    public function updatePeriods($importId)
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if ($redirect = $this->checkAdmin()) return $redirect;

        $import = $this->importModel->find($importId);
        if (!$import) {
            return redirect()->to('/asc-import')->with('error', 'Data tidak ditemukan!');
        }

        $periods = $this->request->getPost('periods');
        if (!$periods || !is_array($periods)) {
            return redirect()->back()->with('error', 'Data tidak valid!');
        }

        $db = \Config\Database::connect();
        $db->transStart();

        try {
            foreach ($periods as $periodId => $data) {
                // Update di tabel asc_periods
                $this->periodModel->update($periodId, [
                    'start_time' => $data['start_time'],
                    'end_time'   => $data['end_time'],
                    'name'       => $data['name'] ?? null,
                ]);

                // Update juga di asc_schedules
                $period = $this->periodModel->find($periodId);
                if ($period) {
                    $this->scheduleModel->where('import_id', $importId)
                        ->where('period_number', $period['period_number'])
                        ->set([
                            'start_time' => $data['start_time'],
                            'end_time'   => $data['end_time'],
                        ])
                        ->update();
                }
            }

            $db->transComplete();

            if ($db->transStatus() === false) {
                throw new \Exception('Gagal menyimpan perubahan!');
            }

            return redirect()->to('/asc-import/edit-periods/' . $importId)
                ->with('success', 'Jam pelajaran berhasil diperbarui!');

        } catch (\Exception $e) {
            $db->transRollback();
            return redirect()->back()->with('error', $e->getMessage());
        }
    }

    public function updateMetadata($id)
    {
        if ($redirect = $this->checkLogin()) return $redirect;
        if ($redirect = $this->checkAdmin()) return $redirect;

        $import = $this->importModel->find($id);
        if (!$import) {
            return redirect()->to('/asc-import')->with('error', 'Data tidak ditemukan!');
        }

        $rules = [
            'name'          => 'required|max_length[100]',
            'academic_year' => 'required|max_length[20]',
            'semester'      => 'required|in_list[Ganjil,Genap]',
        ];

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

        $this->importModel->update($id, [
            'name'          => $this->request->getPost('name'),
            'academic_year' => $this->request->getPost('academic_year'),
            'semester'      => $this->request->getPost('semester'),
            'notes'         => $this->request->getPost('notes'),
        ]);

        return redirect()->to('/asc-import')->with('success', 'Metadata jadwal berhasil diperbarui!');
    }
}