<?php

namespace App\Controllers\Admin;

use App\Controllers\BaseController;
use App\Models\ScheduleModel;
use App\Models\ScheduleEntryModel;

/**
 * ScheduleExport Controller
 * Route:
 *   GET /schedule-generator/export-excel/{id}/{type}
 *   GET /schedule-generator/export-pdf/{id}/{type}
 *
 * Type: master | per-class | per-teacher
 */
class ScheduleExport extends BaseController
{
    protected ScheduleModel      $scheduleModel;
    protected ScheduleEntryModel $entryModel;
    protected \CodeIgniter\Database\BaseConnection $db;

    public function __construct()
    {
        $this->scheduleModel = new ScheduleModel();
        $this->entryModel    = new ScheduleEntryModel();
        $this->db            = \Config\Database::connect();
    }

    private function hslToHex(float $h, float $s, float $l): string
    {
        $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);
    }

    private function getTeacherColorHex(int $teacherId): string
    {
        $hue = ($teacherId * 137.5) % 360;
        $sat = 70 + ($teacherId % 3) * 15;
        $lit = 40 + (($teacherId * 3) % 4) * 15;
        return $this->hslToHex($hue, $sat, $lit);
    }

    // ─────────────────────────────────────────────────────────────
    // HELPER: ambil data lengkap jadwal
    // ─────────────────────────────────────────────────────────────
    private function getScheduleData(int $id): ?array
    {
        $schedule = $this->scheduleModel->getWithRelations($id);
        if (!$schedule) return null;

        $activeDays = array_map('intval', explode(',', $schedule['active_days']));

        // Timeslots
        $timeslots = $this->db->table('schedule_timeslots')
            ->whereIn('day', $activeDays)
            ->where('is_active', 1)
            ->orderBy('day')->orderBy('slot_number')
            ->get()->getResultArray();

        // Semua entri dengan join
        $entries = $this->db->table('schedule_entries se')
            ->select([
                'se.*',
                't.name as teacher_name', 't.nip as teacher_nip', 't.short_code as teacher_short_code',
                '(SELECT MIN(color) FROM asc_teachers WHERE teacher_id = t.id) as teacher_color',
                'ss.name as subject_name', 'ss.code as subject_code',
                'c.name as classroom_name',
                'g.name as grade_name', 'g.order as grade_order',
            ])
            ->join('teachers t',         't.id = se.teacher_id',         'left')
            ->join('school_subjects ss', 'ss.id = se.school_subject_id', 'left')
            ->join('classrooms c',       'c.id = se.classroom_id',       'left')
            ->join('grades g',           'g.id = c.grade_id',            'left')
            ->where('se.schedule_id', $id)
            ->orderBy('se.day')->orderBy('se.slot_number')
            ->get()->getResultArray();

        // Assign dynamic unique colors
        foreach ($entries as &$e) {
            $tid = (int)$e['teacher_id'];
            if ($tid > 0) {
                $e['teacher_color'] = $this->getTeacherColorHex($tid);
            } else {
                $e['teacher_color'] = '#CCCCCC';
            }
        }
        unset($e);

        // Kelas unik
        $classrooms = [];
        foreach ($entries as $e) {
            $cid = $e['classroom_id'];
            if (!isset($classrooms[$cid])) {
                $classrooms[$cid] = [
                    'id'         => $cid,
                    'name'       => $e['classroom_name'],
                    'grade_name' => $e['grade_name'],
                    'grade_order'=> (int)$e['grade_order'],
                    'full_name'  => trim($e['classroom_name']),
                ];
            }
        }
        uasort($classrooms, fn($a,$b) => $a['grade_order'] <=> $b['grade_order'] ?: strcmp($a['name'],$b['name']));

        // Guru unik
        $teachers = [];
        foreach ($entries as $e) {
            $tid = $e['teacher_id'];
            if (!isset($teachers[$tid])) {
                $teachers[$tid] = [
                    'id'         => $tid,
                    'name'       => $e['teacher_name'],
                    'nip'        => $e['teacher_nip'],
                    'short_code' => $e['teacher_short_code'] ?: ('G' . $tid),
                    'color'      => $e['teacher_color'] ?: '#CCCCCC',
                    'subjects'   => [],
                ];
            }
            if ($e['subject_name']) {
                $teachers[$tid]['subjects'][$e['subject_name']] = true;
            }
        }
        uasort($teachers, fn($a,$b) => strnatcasecmp($a['short_code'], $b['short_code']));

        // Slot KBM per hari (untuk header)
        $kbmSlots = [];
        foreach ($timeslots as $ts) {
            if ($ts['slot_type'] === 'kbm') {
                $kbmSlots[$ts['day']][] = $ts;
            }
        }

        // Grid [day][slot][classroom_id] = entry
        $grid = [];
        foreach ($entries as $e) {
            $grid[(int)$e['day']][(int)$e['slot_number']][(int)$e['classroom_id']] = $e;
        }

        // Grid per guru [teacher_id][day][slot] = entry
        $gridTeacher = [];
        foreach ($entries as $e) {
            $gridTeacher[(int)$e['teacher_id']][(int)$e['day']][(int)$e['slot_number']] = $e;
        }

        $dayNames = ['','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'];

        // Ambil nama sekolah dari settings
        $schoolSettingModel = new \App\Models\SchoolSettingModel();
        $schoolSettings = $schoolSettingModel->getSettings();
        $schoolName = $schoolSettings['school_name'] ?? 'Sekolah';

        return compact('schedule','activeDays','timeslots','entries','classrooms','teachers','kbmSlots','grid','gridTeacher','dayNames','schoolName');
    }

    // ─────────────────────────────────────────────────────────────
    // EXCEL EXPORT
    // ─────────────────────────────────────────────────────────────
    public function exportExcel(int $id, string $type = 'master')
    {
        $data = $this->getScheduleData($id);
        if (!$data) {
            return redirect()->back()->with('error', 'Jadwal tidak ditemukan.');
        }

        $spreadsheet = new \PhpOffice\PhpSpreadsheet\Spreadsheet();
        $spreadsheet->removeSheetByIndex(0);

        switch ($type) {
            case 'per-class':
                $this->buildExcelPerClass($spreadsheet, $data);
                $filename = 'jadwal_per_kelas_' . $id;
                break;
            case 'per-teacher':
                $this->buildExcelPerTeacher($spreadsheet, $data);
                $filename = 'jadwal_per_guru_' . $id;
                break;
            case 'master-teacher':
                $this->buildExcelMaster($spreadsheet, $data, true);
                $filename = 'jadwal_master_hanya_kode_guru_' . $id;
                break;
            default:
                $this->buildExcelMaster($spreadsheet, $data, false);
                $filename = 'jadwal_master_' . $id;
        }

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

        $writer = \PhpOffice\PhpSpreadsheet\IOFactory::createWriter($spreadsheet, 'Xlsx');
        $writer->save('php://output');
        exit;
    }

    // ── Excel Master ─────────────────────────────────────────────
    private function buildExcelMaster(\PhpOffice\PhpSpreadsheet\Spreadsheet $sp, array $d, bool $teacherOnly = false): void
    {
        $sheet = $sp->createSheet();
        $sheet->setTitle('Master Timetable');
        $sp->setActiveSheetIndex($sp->getIndex($sheet));

        $dayNames   = $d['dayNames'];
        $activeDays = $d['activeDays'];
        $classrooms = $d['classrooms'];
        $kbmSlots   = $d['kbmSlots'];
        $grid       = $d['grid'];
        $schedule   = $d['schedule'];
        $teachers   = $d['teachers'];
        $schoolName = $d['schoolName'];

        $Coord = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::class;

        $styleHeader = [
            'font'      => ['bold'=>true,'size'=>9,'color'=>['rgb'=>'FFFFFF']],
            'fill'      => ['fillType'=>'solid','startColor'=>['rgb'=>'1e3a5f']],
            'alignment' => ['horizontal'=>'center','vertical'=>'center','wrapText'=>true],
            'borders'   => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'555555']]],
        ];
        $styleDay = [
            'font'      => ['bold'=>true,'size'=>9,'color'=>['rgb'=>'FFFFFF']],
            'fill'      => ['fillType'=>'solid','startColor'=>['rgb'=>'1e3a5f']],
            'alignment' => ['horizontal'=>'center','vertical'=>'center'],
            'borders'   => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'555555']]],
        ];
        $styleSlot = [
            'font'      => ['bold'=>true,'size'=>8,'color'=>['rgb'=>'FFFFFF']],
            'fill'      => ['fillType'=>'solid','startColor'=>['rgb'=>'2d4f7c']],
            'alignment' => ['horizontal'=>'center','vertical'=>'center','wrapText'=>true],
            'borders'   => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'555555']]],
        ];

        // Page Setup A4 Landscape
        $sheet->getPageSetup()
            ->setPaperSize(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::PAPERSIZE_A4)
            ->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
        $sheet->getPageMargins()->setTop(0.5)->setBottom(0.5)->setLeft(0.5)->setRight(0.5);

        $totalCols = count($classrooms) + 2;
        $lastColStr = $Coord::stringFromColumnIndex($totalCols);

        // Judul 1: Nama Sekolah
        $sheet->setCellValue('A1', strtoupper($schoolName));
        $sheet->mergeCells('A1:' . $lastColStr . '1');
        $sheet->getStyle('A1')->applyFromArray([
            'font'      => ['bold'=>true,'size'=>14],
            'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
        ]);
        $sheet->getRowDimension(1)->setRowHeight(24);

        // Judul 2: Jadwal Master
        $sheet->setCellValue('A2', strtoupper($schedule['name']) . ' — MASTER TIMETABLE');
        $sheet->mergeCells('A2:' . $lastColStr . '2');
        $sheet->getStyle('A2')->applyFromArray([
            'font'      => ['bold'=>true,'size'=>12],
            'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
        ]);
        $sheet->getRowDimension(2)->setRowHeight(22);

        // Judul 3: Periode/Semester
        $sheet->setCellValue('A3', 'Tahun Ajaran ' . $schedule['year_name'] . ' — Semester ' . $schedule['period_name']);
        $sheet->mergeCells('A3:' . $lastColStr . '3');
        $sheet->getStyle('A3')->applyFromArray([
            'font'      => ['size'=>9,'italic'=>true],
            'alignment' => ['horizontal'=>'center','vertical'=>'center'],
        ]);
        $sheet->getRowDimension(3)->setRowHeight(18);

        // Header baris 5: Hari | Jam | Kelas...
        $row = 5;
        $sheet->setCellValue('A' . $row, 'Hari');
        $sheet->setCellValue('B' . $row, 'Slot / Jam');
        $col = 3;
        foreach ($classrooms as $cls) {
            $colLetter = $Coord::stringFromColumnIndex($col);
            $sheet->setCellValue($colLetter . $row, $cls['full_name']);
            $sheet->getColumnDimension($colLetter)->setWidth(11);
            $col++;
        }
        $sheet->getStyle('A5:' . $Coord::stringFromColumnIndex($col-1) . '5')->applyFromArray($styleHeader);
        $sheet->getRowDimension(5)->setRowHeight(22);
        $sheet->getColumnDimension('A')->setWidth(9);
        $sheet->getColumnDimension('B')->setWidth(8);

        $row = 6;
        foreach ($activeDays as $dayIdx => $day) {
            $slots    = $kbmSlots[$day] ?? [];
            if (empty($slots)) continue;
            $dayStart = $row;

            foreach ($slots as $slotIdx => $slot) {
                $sheet->setCellValue('A' . $row, strtoupper(substr($dayNames[$day], 0, 3)));
                $sheet->setCellValue('B' . $row, ($slot['label'] ?? $slot['slot_number']) . "\n" . substr($slot['start_time'],0,5));
                $sheet->getStyle('B' . $row)->applyFromArray($styleSlot);
                $sheet->getRowDimension($row)->setRowHeight(30);

                $col = 3;
                foreach ($classrooms as $cid => $cls) {
                    $entry     = $grid[$day][$slot['slot_number']][$cid] ?? null;
                    $colLetter = $Coord::stringFromColumnIndex($col);
                    if ($entry) {
                        $displayCode = $entry['subject_code'] ?: mb_substr($entry['subject_name'], 0, 10);
                        $displayTeacherCode = $entry['teacher_short_code'] ?: mb_substr($entry['teacher_name'], 0, 3);
                        
                        if ($teacherOnly) {
                            $val = $displayTeacherCode;
                        } else {
                            $val = $displayCode . "\n[" . $displayTeacherCode . "]";
                        }
                        
                        $bg = ltrim($entry['teacher_color'] ?: '#FFFFFF', '#');
                        $fg = $this->getExcelTextColor($bg);

                        $sheet->setCellValue($colLetter . $row, $val);
                        $sheet->getStyle($colLetter . $row)->applyFromArray([
                            'font'      => ['bold'=>true,'size'=>8,'color'=>['rgb'=>$fg]],
                            'fill'      => ['fillType'=>'solid','startColor'=>['rgb'=>$bg]],
                            'alignment' => ['horizontal'=>'center','vertical'=>'center','wrapText'=>true],
                            'borders'   => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'AAAAAA']]],
                        ]);
                    } else {
                        $sheet->getStyle($colLetter . $row)->applyFromArray([
                            'fill'    => ['fillType'=>'solid','startColor'=>['rgb'=>'F5F5F5']],
                            'borders' => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'DDDDDD']]],
                        ]);
                    }
                    $col++;
                }
                $row++;
            }

            // Merge kolom Hari
            if ($row - $dayStart > 1) {
                $sheet->mergeCells('A' . $dayStart . ':A' . ($row-1));
            }
            $sheet->getStyle('A' . $dayStart . ':A' . ($row-1))->applyFromArray($styleDay);

            // Pemisah hari
            $sheet->getRowDimension($row)->setRowHeight(4);
            $sheet->mergeCells("A{$row}:{$lastColStr}{$row}");
            $sheet->getStyle("A{$row}:{$lastColStr}{$row}")->applyFromArray([
                'fill' => ['fillType' => 'solid', 'startColor' => ['rgb' => '1e3a5f']],
            ]);
            $row++;
        }

        // Legenda Guru di bawah
        $row++;
        $sheet->mergeCells("A{$row}:{$lastColStr}{$row}");
        $sheet->setCellValue('A' . $row, 'KETERANGAN KODE GURU');
        $sheet->getStyle('A' . $row)->applyFromArray([
            'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 10],
            'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '1e3a5f']],
            'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
        ]);
        $sheet->getRowDimension(row: $row)->setRowHeight(18);
        $row++;

        $legendCols = 4;
        $legendPerCol = ceil(count($teachers) / $legendCols);
        
        // Header Legenda
        for ($colIdx = 0; $colIdx < $legendCols; $colIdx++) {
            $colLetter = $Coord::stringFromColumnIndex($colIdx * 4 + 1);
            $colLetterName = $Coord::stringFromColumnIndex($colIdx * 4 + 2);
            $colLetterNameEnd = $Coord::stringFromColumnIndex($colIdx * 4 + 3);
            $sheet->setCellValue($colLetter . $row, 'Kode');
            $sheet->setCellValue($colLetterName . $row, 'Nama Guru');
            $sheet->mergeCells($colLetterName . $row . ':' . $colLetterNameEnd . $row);
            $sheet->getStyle($colLetter . $row . ':' . $colLetterNameEnd . $row)->applyFromArray([
                'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 9],
                'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '2d4f7c']],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '555555']]],
            ]);
        }
        $row++;

        $teacherArray = array_values($teachers);
        for ($i = 0; $i < $legendPerCol; $i++) {
            for ($cIdx = 0; $cIdx < $legendCols; $cIdx++) {
                $idx = $i + ($cIdx * $legendPerCol);
                if (!isset($teacherArray[$idx])) continue;

                $teacher = $teacherArray[$idx];
                $bg = ltrim($teacher['color'] ?: '#CCCCCC', '#');
                $fg = $this->getExcelTextColor($bg);
                $colLetter = $Coord::stringFromColumnIndex($cIdx * 4 + 1);
                $colLetterName = $Coord::stringFromColumnIndex($cIdx * 4 + 2);
                $colLetterNameEnd = $Coord::stringFromColumnIndex($cIdx * 4 + 3);

                $subjectsTaught = implode(', ', array_keys($teacher['subjects']));
                $nameVal = $teacher['name'] . ($subjectsTaught ? ' (Mengajar: ' . $subjectsTaught . ')' : '');

                $sheet->setCellValue($colLetter . $row, $teacher['short_code']);
                $sheet->setCellValue($colLetterName . $row, $nameVal);
                $sheet->mergeCells($colLetterName . $row . ':' . $colLetterNameEnd . $row);

                $sheet->getStyle($colLetter . $row)->applyFromArray([
                    'font'      => ['bold' => true, 'color' => ['rgb' => $fg], 'size' => 9],
                    'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => $bg]],
                    'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                    'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'AAAAAA']]],
                ]);
                $sheet->getStyle($colLetterName . $row . ':' . $colLetterNameEnd . $row)->applyFromArray([
                    'font'    => ['size' => 9],
                    'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'AAAAAA']]],
                    'alignment' => ['vertical' => 'center'],
                ]);
            }
            $sheet->getRowDimension($row)->setRowHeight(18);
            $row++;
        }

        // Set print area
        $sheet->getPageSetup()->setPrintArea("A1:{$lastColStr}" . ($row - 1));

        // Freeze panes
        $sheet->freezePane('C6');
    }

    // ── Excel Per Kelas ──────────────────────────────────────────
    private function buildExcelPerClass(\PhpOffice\PhpSpreadsheet\Spreadsheet $sp, array $d): void
    {
        $dayNames   = $d['dayNames'];
        $activeDays = $d['activeDays'];
        $kbmSlots   = $d['kbmSlots'];
        $grid       = $d['grid'];
        $timeslots  = $d['timeslots'];
        $schoolName = $d['schoolName'];
        $teachers   = $d['teachers'];

        $Coord = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::class;

        foreach ($d['classrooms'] as $cid => $cls) {
            $sheet = $sp->createSheet();
            $title = mb_substr(preg_replace('/[^\w\s]/', '', $cls['full_name']), 0, 31);
            $sheet->setTitle($title ?: 'Kelas_' . $cid);

            // Page Setup A4 Landscape
            $sheet->getPageSetup()
                ->setPaperSize(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::PAPERSIZE_A4)
                ->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
            $sheet->getPageMargins()->setTop(0.5)->setBottom(0.5)->setLeft(0.5)->setRight(0.5);

            $colDays = count($activeDays);
            $lastDataCol = $colDays + 2;
            $lastColStr  = $Coord::stringFromColumnIndex($lastDataCol);

            // Judul 1: Nama Sekolah
            $sheet->setCellValue('A1', strtoupper($schoolName));
            $sheet->mergeCells("A1:{$lastColStr}1");
            $sheet->getStyle('A1')->applyFromArray([
                'font'      => ['bold' => true, 'size' => 14],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
            ]);
            $sheet->getRowDimension(1)->setRowHeight(24);

            // Judul 2: Jadwal Kelas
            $sheet->setCellValue('A2', 'JADWAL PELAJARAN KELAS ' . strtoupper($cls['full_name']));
            $sheet->mergeCells("A2:{$lastColStr}2");
            $sheet->getStyle('A2')->applyFromArray([
                'font'      => ['bold' => true, 'size' => 12],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
            ]);
            $sheet->getRowDimension(2)->setRowHeight(22);

            // Judul 3: Periode/Semester
            $sheet->setCellValue('A3', 'Tahun Ajaran ' . $d['schedule']['year_name'] . ' — Semester ' . $d['schedule']['period_name']);
            $sheet->mergeCells("A3:{$lastColStr}3");
            $sheet->getStyle('A3')->applyFromArray([
                'font'      => ['size' => 9, 'italic' => true],
                'alignment' => ['horizontal' => 'center'],
            ]);
            $sheet->getRowDimension(3)->setRowHeight(18);

            // Header kolom
            $headerStyle = [
                'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 9],
                'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '1e3a5f']],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center', 'wrapText' => true],
                'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '555555']]],
            ];

            $sheet->setCellValue('A5', 'Jam');
            $sheet->setCellValue('B5', 'Waktu');
            $sheet->getStyle('A5:B5')->applyFromArray($headerStyle);
            $sheet->getColumnDimension('A')->setWidth(8);
            $sheet->getColumnDimension('B')->setWidth(14);

            foreach ($activeDays as $i => $day) {
                $col = $Coord::stringFromColumnIndex($i + 3);
                $sheet->setCellValue($col . '5', $dayNames[$day]);
                $sheet->getStyle($col . '5')->applyFromArray($headerStyle);
                $sheet->getColumnDimension($col)->setWidth(16);
            }
            $sheet->getRowDimension(5)->setRowHeight(22);

            // Kumpulkan slot unik
            $allSlotNums = [];
            foreach ($timeslots as $ts) $allSlotNums[$ts['slot_number']] = $ts;
            ksort($allSlotNums);

            $row = 6;
            $usedTeachers = [];

            foreach ($allSlotNums as $slotNum => $slotRef) {
                $isKbm = false;
                foreach ($activeDays as $day) {
                    $dayTs = array_filter($timeslots, fn($t) => $t['day']==$day && $t['slot_number']==$slotNum);
                    $dayTs = reset($dayTs);
                    if ($dayTs && $dayTs['slot_type'] === 'kbm') { $isKbm = true; break; }
                }

                $sheet->setCellValue('A' . $row, $slotRef['label'] ?? $slotNum);
                $sheet->setCellValue('B' . $row, substr($slotRef['start_time'],0,5).'–'.substr($slotRef['end_time'],0,5));
                $sheet->getStyle('A' . $row . ':B' . $row)->applyFromArray([
                    'alignment'=>['horizontal'=>'center','vertical'=>'center'],
                    'borders'=>['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'E2E8F0']]],
                ]);

                if (!$isKbm) {
                    // Non-KBM row
                    $icons = ['istirahat'=>'☕','upacara'=>'🚩','keagamaan'=>'🌙'];
                    $ico   = $icons[$slotRef['slot_type']] ?? '•';
                    $label = $ico . ' ' . ($slotRef['label'] ?? $slotRef['slot_type']);
                    $endCol= $Coord::stringFromColumnIndex(count($activeDays)+2);
                    $sheet->mergeCells('C'.$row.':'.$endCol.$row);
                    $sheet->setCellValue('C' . $row, $label);
                    $sheet->getStyle('A'.$row.':'.$endCol.$row)->applyFromArray([
                        'fill'=>['fillType'=>'solid','startColor'=>['rgb'=>'FFFBEB']],
                        'font'=>['italic'=>true,'size'=>9],
                        'alignment'=>['horizontal'=>'center','vertical'=>'center'],
                        'borders'=>['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'E2E8F0']]],
                    ]);
                    $sheet->getRowDimension(row: $row)->setRowHeight(24);
                } else {
                    foreach ($activeDays as $i => $day) {
                        $colLetter = $Coord::stringFromColumnIndex($i + 3);
                        $entry  = $grid[$day][$slotNum][$cid] ?? null;
                        
                        if ($entry) {
                            $displayTeacherCode = $entry['teacher_short_code'] ?: mb_substr($entry['teacher_name'], 0, 3);
                            $val = $entry['subject_name'] . "\n[" . $displayTeacherCode . "]";
                            
                            $bg = ltrim($entry['teacher_color'] ?: '#FFFFFF', '#');
                            $fg = $this->getExcelTextColor($bg);

                            $sheet->setCellValue($colLetter . $row, $val);
                            $sheet->getStyle($colLetter . $row)->applyFromArray([
                                'font'      => ['bold'=>true,'size'=>8,'color'=>['rgb'=>$fg]],
                                'fill'      => ['fillType'=>'solid','startColor'=>['rgb'=>$bg]],
                                'alignment' => ['horizontal'=>'center','vertical'=>'center','wrapText'=>true],
                                'borders'   => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'AAAAAA']]],
                            ]);
                            $usedTeachers[$displayTeacherCode] = $entry['teacher_name'];
                        } else {
                            $sheet->setCellValue($colLetter . $row, '');
                            $sheet->getStyle($colLetter . $row)->applyFromArray([
                                'fill'    => ['fillType'=>'solid','startColor'=>['rgb'=>'FAFAFA']],
                                'borders' => ['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'DDDDDD']]],
                            ]);
                        }
                    }
                    $sheet->getRowDimension($row)->setRowHeight(36);
                }
                $row++;
            }

            // Keterangan Kode Guru di bawah
            if (!empty($usedTeachers)) {
                $row++;
                $sheet->mergeCells("A{$row}:{$lastColStr}{$row}");
                $sheet->setCellValue('A' . $row, 'KETERANGAN KODE GURU');
                $sheet->getStyle('A' . $row)->applyFromArray([
                    'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 10],
                    'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '1e3a5f']],
                    'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                ]);
                $sheet->getRowDimension($row)->setRowHeight(20);
                $row++;

                // 2 kolom legenda
                ksort($usedTeachers);
                $usedTeacherList = [];
                foreach ($usedTeachers as $code => $name) {
                    $tColor = '#CCCCCC';
                    foreach ($teachers as $t) {
                        if ($t['short_code'] === $code || $t['name'] === $name) {
                            $tColor = $t['color'];
                            break;
                        }
                    }
                    $usedTeacherList[] = [
                        'code' => $code,
                        'name' => $name,
                        'color' => $tColor
                    ];
                }

                $legendCols = 2;
                $legendRows = ceil(count($usedTeacherList) / $legendCols);

                // Header
                for ($col = 0; $col < $legendCols; $col++) {
                    $colLetter = $Coord::stringFromColumnIndex($col * 3 + 1);
                    $colLetterName = $Coord::stringFromColumnIndex($col * 3 + 2);
                    $colLetterNameEnd = $Coord::stringFromColumnIndex($col * 3 + 3);
                    $sheet->setCellValue($colLetter . $row, 'Kode');
                    $sheet->setCellValue($colLetterName . $row, 'Nama Guru');
                    $sheet->mergeCells($colLetterName . $row . ':' . $colLetterNameEnd . $row);
                    $sheet->getStyle($colLetter . $row . ':' . $colLetterNameEnd . $row)->applyFromArray([
                        'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 9],
                        'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '2d4f7c']],
                        'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                        'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '555555']]],
                    ]);
                }
                $row++;

                for ($i = 0; $i < $legendRows; $i++) {
                    // Kolom 1
                    $idx1 = $i;
                    if (isset($usedTeacherList[$idx1])) {
                        $t = $usedTeacherList[$idx1];
                        $bg = ltrim($t['color'] ?: '#CCCCCC', '#');
                        $fg = $this->getExcelTextColor($bg);
                        $sheet->setCellValue('A' . $row, $t['code']);
                        $sheet->setCellValue('B' . $row, $t['name']);
                        $sheet->mergeCells('B' . $row . ':C' . $row);

                        $sheet->getStyle('A' . $row)->applyFromArray([
                            'font'      => ['bold' => true, 'color' => ['rgb' => $fg], 'size' => 9],
                            'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => $bg]],
                            'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                            'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'AAAAAA']]],
                        ]);
                        $sheet->getStyle('B' . $row . ':C' . $row)->applyFromArray([
                            'font'    => ['size' => 9],
                            'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'AAAAAA']]],
                            'alignment' => ['vertical' => 'center'],
                        ]);
                    }

                    // Kolom 2
                    $idx2 = $i + $legendRows;
                    if (isset($usedTeacherList[$idx2])) {
                        $t = $usedTeacherList[$idx2];
                        $bg = ltrim($t['color'] ?: '#CCCCCC', '#');
                        $fg = $this->getExcelTextColor($bg);
                        $colLetterD = $Coord::stringFromColumnIndex(4);
                        $colLetterE = $Coord::stringFromColumnIndex(5);
                        $colLetterF = $Coord::stringFromColumnIndex(6);
                        $sheet->setCellValue($colLetterD . $row, $t['code']);
                        $sheet->setCellValue($colLetterE . $row, $t['name']);
                        $sheet->mergeCells($colLetterE . $row . ':' . $colLetterF . $row);

                        $sheet->getStyle($colLetterD . $row)->applyFromArray([
                            'font'      => ['bold' => true, 'color' => ['rgb' => $fg], 'size' => 9],
                            'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => $bg]],
                            'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                            'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'AAAAAA']]],
                        ]);
                        $sheet->getStyle($colLetterE . $row . ':' . $colLetterF . $row)->applyFromArray([
                            'font'    => ['size' => 9],
                            'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'AAAAAA']]],
                            'alignment' => ['vertical' => 'center'],
                        ]);
                    }
                    $sheet->getRowDimension($row)->setRowHeight(18);
                    $row++;
                }
            }

            // Set print area
            $sheet->getPageSetup()->setPrintArea("A1:{$lastColStr}" . ($row - 1));

            // Freeze pane
            $sheet->freezePane('C6');
        }

        if ($sp->getSheetCount() > 0) $sp->setActiveSheetIndex(0);
    }

    // ── Excel Per Guru ───────────────────────────────────────────
    private function buildExcelPerTeacher(\PhpOffice\PhpSpreadsheet\Spreadsheet $sp, array $d): void
    {
        $dayNames    = $d['dayNames'];
        $activeDays  = $d['activeDays'];
        $gridTeacher = $d['gridTeacher'];
        $timeslots   = $d['timeslots'];
        $schoolName  = $d['schoolName'];

        $Coord = \PhpOffice\PhpSpreadsheet\Cell\Coordinate::class;

        foreach ($d['teachers'] as $tid => $teacher) {
            $sheet = $sp->createSheet();
            $title = mb_substr(preg_replace('/[^\w\s]/', '', $teacher['name']), 0, 31);
            $sheet->setTitle($title ?: 'Guru_' . $tid);

            // Page Setup A4 Landscape
            $sheet->getPageSetup()
                ->setPaperSize(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::PAPERSIZE_A4)
                ->setOrientation(\PhpOffice\PhpSpreadsheet\Worksheet\PageSetup::ORIENTATION_LANDSCAPE);
            $sheet->getPageMargins()->setTop(0.5)->setBottom(0.5)->setLeft(0.5)->setRight(0.5);

            $bgColor = ltrim($teacher['color'] ?: '#CCCCCC', '#');
            $fgColor = $this->getExcelTextColor($bgColor);

            $colDays = count($activeDays);
            $lastDataCol = $colDays + 2;
            $lastColStr  = $Coord::stringFromColumnIndex($lastDataCol);

            // Judul 1: Nama Sekolah
            $sheet->setCellValue('A1', strtoupper($schoolName));
            $sheet->mergeCells("A1:{$lastColStr}1");
            $sheet->getStyle('A1')->applyFromArray([
                'font'      => ['bold' => true, 'size' => 14],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
            ]);
            $sheet->getRowDimension(1)->setRowHeight(24);

            // Judul 2: Jadwal Mengajar Guru (dengan warna guru)
            $sheet->setCellValue('A2', 'JADWAL MENGAJAR — ' . strtoupper($teacher['name']));
            $sheet->mergeCells("A2:{$lastColStr}2");
            $sheet->getStyle('A2')->applyFromArray([
                'font'      => ['bold' => true, 'size' => 12, 'color' => ['rgb' => $fgColor]],
                'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => $bgColor]],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
            ]);
            $sheet->getRowDimension(2)->setRowHeight(22);

            // Judul 3: NIP & Semester
            $subTitle = $teacher['nip'] ? 'NIP: ' . $teacher['nip'] . ' | ' : '';
            $subTitle .= 'Tahun Ajaran ' . $d['schedule']['year_name'] . ' — Semester ' . $d['schedule']['period_name'];
            $sheet->setCellValue('A3', $subTitle);
            $sheet->mergeCells("A3:{$lastColStr}3");
            $sheet->getStyle('A3')->applyFromArray([
                'font'      => ['size' => 9, 'italic' => true],
                'alignment' => ['horizontal' => 'center'],
            ]);
            $sheet->getRowDimension(3)->setRowHeight(18);

            // Header kolom (Jam | Waktu | Hari-hari)
            $headerStyle = [
                'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 9],
                'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '1e3a5f']],
                'alignment' => ['horizontal' => 'center', 'vertical' => 'center', 'wrapText' => true],
                'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '555555']]],
            ];

            $sheet->setCellValue('A5', 'Jam');
            $sheet->setCellValue('B5', 'Waktu');
            $sheet->getStyle('A5:B5')->applyFromArray($headerStyle);
            $sheet->getColumnDimension('A')->setWidth(8);
            $sheet->getColumnDimension('B')->setWidth(14);

            foreach ($activeDays as $i => $day) {
                $col = $Coord::stringFromColumnIndex($i + 3);
                $sheet->setCellValue($col . '5', $dayNames[$day]);
                $sheet->getStyle($col . '5')->applyFromArray($headerStyle);
                $sheet->getColumnDimension($col)->setWidth(16);
            }
            $sheet->getRowDimension(5)->setRowHeight(22);

            $allSlotNums = [];
            foreach ($timeslots as $ts) $allSlotNums[$ts['slot_number']] = $ts;
            ksort($allSlotNums);

            $row = 6;
            $totalHours = 0;
            $classSummary = [];

            foreach ($allSlotNums as $slotNum => $slotRef) {
                $isKbm = false;
                foreach ($activeDays as $day) {
                    $dayTs = array_filter($timeslots, fn($t) => $t['day']==$day && $t['slot_number']==$slotNum);
                    $dayTs = reset($dayTs);
                    if ($dayTs && $dayTs['slot_type'] === 'kbm') { $isKbm = true; break; }
                }

                $sheet->setCellValue('A' . $row, $slotRef['label'] ?? $slotNum);
                $sheet->setCellValue('B' . $row, substr($slotRef['start_time'],0,5).'–'.substr($slotRef['end_time'],0,5));
                $sheet->getStyle('A' . $row . ':B' . $row)->applyFromArray([
                    'alignment'=>['horizontal'=>'center','vertical'=>'center'],
                    'borders'=>['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'E2E8F0']]],
                ]);

                if (!$isKbm) {
                    $icons = ['istirahat'=>'☕','upacara'=>'🚩','keagamaan'=>'🌙'];
                    $ico   = $icons[$slotRef['slot_type']] ?? '•';
                    $sheet->mergeCells('C'.$row.':'.$lastColStr.$row);
                    $sheet->setCellValue('C'.$row, $ico.' '.($slotRef['label']??$slotRef['slot_type']));
                    $sheet->getStyle('A'.$row.':'.$lastColStr.$row)->applyFromArray([
                        'fill'=>['fillType'=>'solid','startColor'=>['rgb'=>'FFFBEB']],
                        'font'=>['italic'=>true,'size'=>9],
                        'alignment'=>['horizontal'=>'center','vertical'=>'center'],
                        'borders'=>['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'E2E8F0']]],
                    ]);
                    $sheet->getRowDimension(row: $row)->setRowHeight(24);
                } else {
                    foreach ($activeDays as $i => $day) {
                        $col = $Coord::stringFromColumnIndex($i + 3);
                        $entry = $gridTeacher[$tid][$day][$slotNum] ?? null;
                        if ($entry) {
                            $displayCode = $entry['subject_code'] ?: mb_substr($entry['subject_name'], 0, 10);
                            $val = $entry['classroom_name'] . "\n" . $displayCode;
                            $sheet->setCellValue($col.$row, $val);
                            $sheet->getStyle($col.$row)->applyFromArray([
                                'fill'=>['fillType'=>'solid','startColor'=>['rgb'=>$bgColor]],
                                'font'=>['bold'=>true,'color'=>['rgb'=>$fgColor],'size'=>9],
                                'alignment'=>['horizontal'=>'center','vertical'=>'center','wrapText'=>true],
                                'borders'=>['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'AAAAAA']]],
                            ]);
                            $totalHours++;
                            $key = $entry['classroom_name'];
                            if (!isset($classSummary[$key])) {
                                $classSummary[$key] = ['hours' => 0, 'subjects' => []];
                            }
                            $classSummary[$key]['hours']++;
                            $classSummary[$key]['subjects'][$entry['subject_name']] = true;
                        } else {
                            $sheet->setCellValue($col.$row, '');
                            $sheet->getStyle($col.$row)->applyFromArray([
                                'fill'=>['fillType'=>'solid','startColor'=>['rgb'=>'FFFFFF']],
                                'borders'=>['allBorders'=>['borderStyle'=>'thin','color'=>['rgb'=>'E2E8F0']]],
                            ]);
                        }
                    }
                    $sheet->getRowDimension($row)->setRowHeight(36);
                }
                $row++;
            }

            // Ringkasan Mengajar di bawah
            if (!empty($classSummary)) {
                $row++;
                $sheet->mergeCells("A{$row}:{$lastColStr}{$row}");
                $sheet->setCellValue('A' . $row, 'RINGKASAN MENGAJAR — Total: ' . $totalHours . ' jam/minggu');
                $sheet->getStyle('A' . $row)->applyFromArray([
                    'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 10],
                    'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '1e3a5f']],
                    'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                ]);
                $sheet->getRowDimension($row)->setRowHeight(20);
                $row++;

                // Sub-header
                $sheet->setCellValue('A' . $row, 'Kelas');
                $sheet->mergeCells('B' . $row . ':' . $Coord::stringFromColumnIndex($lastDataCol - 1) . $row);
                $sheet->setCellValue('B' . $row, 'Mata Pelajaran');
                $sheet->setCellValue($lastColStr . $row, 'Jam');
                $sheet->getStyle('A' . $row . ':' . $lastColStr . $row)->applyFromArray([
                    'font'      => ['bold' => true, 'color' => ['rgb' => 'FFFFFF'], 'size' => 9],
                    'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => '2d4f7c']],
                    'alignment' => ['horizontal' => 'center', 'vertical' => 'center'],
                    'borders'   => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => '555555']]],
                ]);
                $row++;

                ksort($classSummary);
                foreach ($classSummary as $className => $summary) {
                    $sheet->setCellValue('A' . $row, $className);
                    $sheet->setCellValue('B' . $row, implode(', ', array_keys($summary['subjects'])));
                    $sheet->mergeCells('B' . $row . ':' . $Coord::stringFromColumnIndex($lastDataCol - 1) . $row);
                    $sheet->setCellValue($lastColStr . $row, $summary['hours']);

                    $sheet->getStyle('A' . $row . ':' . $lastColStr . $row)->applyFromArray([
                        'font'    => ['size' => 9],
                        'borders' => ['allBorders' => ['borderStyle' => 'thin', 'color' => ['rgb' => 'CCCCCC']]],
                        'alignment' => ['vertical' => 'center'],
                    ]);
                    $sheet->getStyle('A' . $row)->applyFromArray([
                        'font'      => ['bold' => true, 'color' => ['rgb' => $fgColor]],
                        'fill'      => ['fillType' => 'solid', 'startColor' => ['rgb' => $bgColor]],
                        'alignment' => ['horizontal' => 'center'],
                    ]);
                    $sheet->getStyle($lastColStr . $row)->getAlignment()->setHorizontal('center');
                    $sheet->getRowDimension($row)->setRowHeight(18);
                    $row++;
                }
            }

            // Set print area
            $sheet->getPageSetup()->setPrintArea("A1:{$lastColStr}" . ($row - 1));

            // Freeze pane
            $sheet->freezePane('C6');
        }

        if ($sp->getSheetCount() > 0) $sp->setActiveSheetIndex(0);
    }

    // ─────────────────────────────────────────────────────────────
    // PDF EXPORT
    // ─────────────────────────────────────────────────────────────
    public function exportPdf(int $id, string $type = 'master')
    {
        $data = $this->getScheduleData($id);
        if (!$data) {
            return redirect()->back()->with('error', 'Jadwal tidak ditemukan.');
        }

        switch ($type) {
            case 'per-class':   return $this->pdfPerClass($data);
            case 'per-teacher': return $this->pdfPerTeacher($data);
            case 'master-teacher': return $this->pdfMaster($data, true);
            default:            return $this->pdfMaster($data, false);
        }
    }

    // ── PDF: buat HTML lalu output ───────────────────────────────
    private function pdfOutput(string $html, string $filename): void
    {
        // Gunakan mPDF jika tersedia, fallback ke HTML download
        if (class_exists('\Mpdf\Mpdf')) {
            $mpdf = new \Mpdf\Mpdf([
                'orientation' => 'L',
                'margin_left' => 8, 'margin_right' => 8,
                'margin_top' => 10, 'margin_bottom' => 10,
                'default_font_size' => 9,
                'default_font' => 'dejavusans',
                'tempDir' => WRITEPATH . 'cache',
            ]);
            $mpdf->SetTitle($filename);
            $mpdf->WriteHTML($html);
            $mpdf->Output($filename . '.pdf', 'D');
            exit;
        }

        // Fallback: output HTML yang bisa diprint/save as PDF dari browser
        header('Content-Type: text/html; charset=utf-8');
        echo $html;
        exit;
    }

    private function pdfMaster(array $d, bool $teacherOnly = false): void
    {
        $html = $this->buildPdfMasterHtml($d, $teacherOnly);
        $filename = $teacherOnly ? 'jadwal_master_hanya_kode_guru_' . $d['schedule']['id'] : 'jadwal_master_' . $d['schedule']['id'];
        $this->pdfOutput($html, $filename);
    }

    private function pdfPerClass(array $d): void
    {
        $html = $this->buildPdfPerClassHtml($d);
        $this->pdfOutput($html, 'jadwal_per_kelas_' . $d['schedule']['id']);
    }

    private function pdfPerTeacher(array $d): void
    {
        $html = $this->buildPdfPerTeacherHtml($d);
        $this->pdfOutput($html, 'jadwal_per_guru_' . $d['schedule']['id']);
    }

    // ── Build HTML PDF Master ────────────────────────────────────
    private function buildPdfMasterHtml(array $d, bool $teacherOnly = false): string
    {
        $schedule   = $d['schedule'];
        $activeDays = $d['activeDays'];
        $dayNames   = $d['dayNames'];
        $classrooms = $d['classrooms'];
        $kbmSlots   = $d['kbmSlots'];
        $grid       = $d['grid'];
        $teachers   = $d['teachers'];
        $schoolName = $d['schoolName'];

        $colWidth = round(84 / max(1, count($classrooms)), 1);

        $html = '
        <style>
            body { font-family: dejavusans, sans-serif; font-size: 8pt; margin: 0; padding: 0; }
            h1 { font-size: 14pt; margin: 0 0 2px; text-align: center; }
            h2 { font-size: 12pt; margin: 0 0 2px; text-align: center; }
            h4 { font-size: 9pt; margin: 0 0 8px; text-align: center; color: #555; font-weight: normal; }
            table.sched-table { width: 100%; border-collapse: collapse; margin-bottom: 10px; }
            table.sched-table th {
                background: #1e3a5f; color: #fff; font-size: 8pt;
                padding: 4px 3px; text-align: center; border: 1px solid #555;
            }
            table.sched-table td {
                padding: 4px 3px; text-align: center;
                border: 1px solid #ccc; font-size: 7.5pt;
                vertical-align: middle;
            }
            .td-hari {
                background: #1e3a5f; color: #fff;
                font-weight: bold; font-size: 8pt;
            }
            .td-jam {
                background: #f0f4f8; font-weight: bold;
            }
            .td-empty { background: #fafafa; }
            .legend-title {
                background: #1e3a5f; color: #fff;
                font-weight: bold; text-align: center;
                padding: 5px;
                font-size: 9pt;
                margin-top: 15px;
            }
            .legend-table {
                width: 100%;
                border-collapse: collapse;
                margin-top: 2px;
            }
            .legend-table th, .legend-table td {
                border: 1px solid #aaa;
                padding: 4px 6px;
                font-size: 8pt;
            }
            .legend-table th {
                background: #2d4f7c;
                color: #fff;
                text-align: center;
            }
            .legend-table .code-cell {
                text-align: center;
                font-weight: bold;
                width: 60px;
            }
            .legend-table .name-cell {
                text-align: left;
            }
        </style>';

        $html .= '<h1>' . strtoupper(htmlspecialchars($schoolName)) . '</h1>';
        $html .= '<h2>JADWAL PELAJARAN — MASTER TIMETABLE</h2>';
        $html .= '<h4>Tahun Ajaran ' . htmlspecialchars($schedule['year_name']) . ' — Semester ' . htmlspecialchars($schedule['period_name']) . '</h4>';

        $html .= '<table class="sched-table"><thead><tr>';
        $html .= '<th style="width:8%">Hari</th>';
        $html .= '<th style="width:8%">Jam</th>';
        foreach ($classrooms as $cls) {
            $html .= '<th style="width:' . $colWidth . '%">' . htmlspecialchars($cls['full_name']) . '</th>';
        }
        $html .= '</tr></thead><tbody>';

        foreach ($activeDays as $dayIdx => $day) {
            $slots = $kbmSlots[$day] ?? [];
            $rowSpan = count($slots);
            if ($rowSpan === 0) continue;

            foreach ($slots as $pIdx => $slot) {
                $isFirst = ($pIdx === 0);
                $html .= '<tr>';
                
                if ($isFirst) {
                    $html .= '<td class="td-hari" rowspan="' . $rowSpan . '" style="vertical-align:middle">';
                    $html .= strtoupper(substr($dayNames[$day], 0, 3));
                    $html .= '</td>';
                }
                
                $html .= '<td class="td-jam">';
                $html .= '<strong>' . ($slot['label'] ?? $slot['slot_number']) . '</strong><br>';
                $html .= '<span style="font-size:6pt">' . substr($slot['start_time'], 0, 5) . '</span>';
                $html .= '</td>';

                foreach ($classrooms as $cid => $cls) {
                    $entry = $grid[$day][$slot['slot_number']][$cid] ?? null;
                    if ($entry) {
                        $bg = ltrim($entry['teacher_color'] ?: '#FFFFFF', '#');
                        $fg = $this->getExcelTextColor($bg);
                        
                        $displayCode = $entry['subject_code'] ?: mb_substr($entry['subject_name'], 0, 10);
                        $displayTeacherCode = $entry['teacher_short_code'] ?: mb_substr($entry['teacher_name'], 0, 3);
                        
                        $html .= '<td style="background:#' . $bg . ';color:#' . $fg . ';font-weight:bold">';
                        if ($teacherOnly) {
                            $html .= htmlspecialchars($displayTeacherCode);
                        } else {
                            $html .= htmlspecialchars($displayCode) . '<br>';
                            $html .= '<span style="font-size:6pt;opacity:0.8">[' . htmlspecialchars($displayTeacherCode) . ']</span>';
                        }
                        $html .= '</td>';
                    } else {
                        $html .= '<td class="td-empty"> </td>';
                    }
                }
                $html .= '</tr>';
            }

            if ($dayIdx < count($activeDays) - 1) {
                $colspan = count($classrooms) + 2;
                $html .= '<tr><td colspan="' . $colspan . '" style="height:3px;background:#1e3a5f;padding:0;border:none"></td></tr>';
            }
        }
        $html .= '</tbody></table>';

        $html .= '<div class="legend-title">KETERANGAN KODE GURU</div>';
        
        $teacherArray = array_values($teachers);
        $legendCols = 4;
        $legendRows = ceil(count($teacherArray) / $legendCols);
        
        $html .= '<table class="legend-table"><thead><tr>';
        for ($col = 0; $col < $legendCols; $col++) {
            $html .= '<th style="width:10%">Kode</th>';
            $html .= '<th style="width:15%">Nama Guru</th>';
        }
        $html .= '</tr></thead><tbody>';

        for ($rowIdx = 0; $rowIdx < $legendRows; $rowIdx++) {
            $html .= '<tr>';
            for ($colIdx = 0; $colIdx < $legendCols; $colIdx++) {
                $idx = $rowIdx + ($colIdx * $legendRows);
                $t = $teacherArray[$idx] ?? null;
                if ($t) {
                    $bg = ltrim($t['color'] ?: '#CCCCCC', '#');
                    $fg = $this->getExcelTextColor($bg);
                    $subjectsTaught = implode(', ', array_keys($t['subjects']));
                    $nameVal = $t['name'] . ($subjectsTaught ? ' (Mengajar: ' . $subjectsTaught . ')' : '');
                    $html .= '<td class="code-cell" style="background:#' . $bg . ';color:#' . $fg . ';font-weight:bold">' . htmlspecialchars($t['short_code']) . '</td>';
                    $html .= '<td class="name-cell" style="background:#' . $bg . '10">' . htmlspecialchars($nameVal) . '</td>';
                } else {
                    $html .= '<td class="code-cell"> </td>';
                    $html .= '<td class="name-cell"> </td>';
                }
            }
            $html .= '</tr>';
        }
        $html .= '</tbody></table>';

        return $html;
    }

    // ── Build HTML PDF Per Kelas ─────────────────────────────────
    private function buildPdfPerClassHtml(array $d): string
    {
        $schedule   = $d['schedule'];
        $activeDays = $d['activeDays'];
        $dayNames   = $d['dayNames'];
        $classrooms = $d['classrooms'];
        $grid       = $d['grid'];
        $timeslots  = $d['timeslots'];
        $schoolName = $d['schoolName'];
        $teachers   = $d['teachers'];

        $allSlotNums = [];
        foreach ($timeslots as $ts) $allSlotNums[$ts['slot_number']] = $ts;
        ksort($allSlotNums);

        $html = '
        <style>
            body { font-family: dejavusans, sans-serif; font-size: 9pt; margin: 0; padding: 0; }
            h1 { font-size: 14pt; margin: 0 0 2px; text-align: center; }
            h2 { font-size: 12pt; margin: 0 0 2px; text-align: center; }
            h4 { font-size: 9pt; margin: 0 0 8px; text-align: center; color: #555; font-weight: normal; }
            .schedule-table { width: 100%; border-collapse: collapse; margin-bottom: 15px; }
            .schedule-table th {
                background: #1e3a5f; color: #fff; font-size: 9pt;
                padding: 6px 4px; text-align: center; border: 1px solid #555;
            }
            .schedule-table td {
                padding: 6px 4px; text-align: center;
                border: 1px solid #ccc; font-size: 9pt;
                vertical-align: middle;
            }
            .td-jam {
                background: #2d4f7c; color: #fff; font-weight: bold; font-size: 9pt;
            }
            .td-empty { background: #f9f9f9; }
            .legend-container { margin-top: 12px; width: 100%; }
            .legend-title { background: #1e3a5f; color: #fff; font-weight: bold; text-align: center; padding: 5px; font-size: 10pt; margin-bottom: 8px; }
            .legend-list { width: 100%; overflow: hidden; }
            .legend-col { width: 48%; float: left; }
            .legend-col-right { width: 48%; float: right; }
            .legend-item { margin-bottom: 2px; font-size: 10pt; line-height: 1.6; }
            .legend-item .code { display: inline-block; width: 50px; font-weight: bold; }
            .legend-item .separator { display: inline-block; width: 15px; text-align: center; }
            .legend-item .name { display: inline-block; }
            .clearfix { clear: both; }
        </style>';

        $isFirst = true;
        foreach ($classrooms as $cid => $cls) {
            if (!$isFirst) {
                $html .= '<div style="page-break-before:always"></div>';
            }
            $isFirst = false;

            $html .= '<h1>' . strtoupper(htmlspecialchars($schoolName)) . '</h1>';
            $html .= '<h2>JADWAL PELAJARAN — KELAS ' . strtoupper(htmlspecialchars($cls['full_name'])) . '</h2>';
            $html .= '<h4>Tahun Ajaran ' . htmlspecialchars($schedule['year_name']) . ' — Semester ' . htmlspecialchars($schedule['period_name']) . '</h4>';

            $colWidth = round(70 / count($activeDays), 1);
            $html .= '<table class="schedule-table"><thead><tr>';
            $html .= '<th style="width:15%">Jam</th>';
            foreach ($activeDays as $day) {
                $html .= '<th style="width:' . $colWidth . '%">' . strtoupper(substr($dayNames[$day], 0, 3)) . '<br><span style="font-size:7pt;font-weight:normal">' . $dayNames[$day] . '</span></th>';
            }
            $html .= '</tr></thead><tbody>';

            $usedTeachers = [];

            foreach ($allSlotNums as $slotNum => $slotRef) {
                $isKbmAny = false;
                foreach ($activeDays as $day) {
                    $ts = array_filter($timeslots, fn($t) => $t['day']==$day && $t['slot_number']==$slotNum);
                    $ts = reset($ts);
                    if ($ts && $ts['slot_type']==='kbm') { $isKbmAny = true; break; }
                }

                if (!$isKbmAny) {
                    $icons = ['istirahat'=>'☕','upacara'=>'🚩','keagamaan'=>'🌙'];
                    $ico   = $icons[$slotRef['slot_type']] ?? '•';
                    $html .= '<tr style="background:#FFFBEB;color:#92400e;font-style:italic"><td class="td-jam">Jam ' . $slotNum . '<br><span style="font-size:7pt">' . substr($slotRef['start_time'], 0, 5) . '-' . substr($slotRef['end_time'], 0, 5) . '</span></td><td colspan="' . count($activeDays) . '">' . $ico . ' ' . esc($slotRef['label']) . '</td></tr>';
                    continue;
                }

                $html .= '<tr><td class="td-jam">'
                    . 'Jam ' . $slotNum . '<br>'
                    . '<span style="font-size:7pt">' . substr($slotRef['start_time'], 0, 5) . '-' . substr($slotRef['end_time'], 0, 5) . '</span>'
                    . '</td>';

                foreach ($activeDays as $day) {
                    $ts = array_filter($timeslots, fn($t) => $t['day']==$day && $t['slot_number']==$slotNum);
                    $ts = reset($ts);
                    if (!$ts || $ts['slot_type'] !== 'kbm') {
                        $html .= '<td class="td-empty">-</td>';
                        continue;
                    }

                    $entry = $grid[$day][$slotNum][$cid] ?? null;
                    if ($entry) {
                        $displayTeacherCode = $entry['teacher_short_code'] ?: mb_substr($entry['teacher_name'], 0, 3);
                        $bg = ltrim($entry['teacher_color'] ?: '#CCCCCC', '#');
                        $fg = $this->getExcelTextColor($bg);
                        
                        $html .= '<td style="background:#' . $bg . ';color:#' . $fg . ';font-weight:bold">'
                            . htmlspecialchars($entry['subject_name'])
                            . '<br><span style="font-size:7pt;opacity:0.8">[' . htmlspecialchars($displayTeacherCode) . ']</span>'
                            . '</td>';
                        
                        $usedTeachers[$displayTeacherCode] = $entry['teacher_name'];
                    } else {
                        $html .= '<td class="td-empty">-</td>';
                    }
                }
                $html .= '</tr>';
            }
            $html .= '</tbody></table>';

            // Keterangan Kode Guru di bawah kelas
            if (!empty($usedTeachers)) {
                ksort($usedTeachers);
                $teacherList = [];
                foreach ($usedTeachers as $code => $name) {
                    $teacherList[] = ['code' => $code, 'name' => $name];
                }
                $totalTeachers = count($teacherList);
                $halfCount = ceil($totalTeachers / 2);

                $html .= '<div class="legend-container">';
                $html .= '<div class="legend-title">KETERANGAN KODE GURU</div>';
                $html .= '<div class="legend-list">';

                // Kolom kiri
                $html .= '<div class="legend-col">';
                for ($i = 0; $i < $halfCount; $i++) {
                    if (isset($teacherList[$i])) {
                        $html .= '<div class="legend-item">';
                        $html .= '<span class="code">' . htmlspecialchars($teacherList[$i]['code']) . '</span>';
                        $html .= '<span class="separator">-</span>';
                        $html .= '<span class="name">' . htmlspecialchars($teacherList[$i]['name']) . '</span>';
                        $html .= '</div>';
                    }
                }
                $html .= '</div>';

                // Kolom kanan
                $html .= '<div class="legend-col-right">';
                for ($i = $halfCount; $i < $totalTeachers; $i++) {
                    if (isset($teacherList[$i])) {
                        $html .= '<div class="legend-item">';
                        $html .= '<span class="code">' . htmlspecialchars($teacherList[$i]['code']) . '</span>';
                        $html .= '<span class="separator">-</span>';
                        $html .= '<span class="name">' . htmlspecialchars($teacherList[$i]['name']) . '</span>';
                        $html .= '</div>';
                    }
                }
                $html .= '</div>';

                $html .= '<div class="clearfix"></div>';
                $html .= '</div></div>';
            }
        }

        return $html;
    }

    // ── Build HTML PDF Per Guru ──────────────────────────────────
    private function buildPdfPerTeacherHtml(array $d): string
    {
        $schedule    = $d['schedule'];
        $activeDays  = $d['activeDays'];
        $dayNames    = $d['dayNames'];
        $teachers    = $d['teachers'];
        $gridTeacher = $d['gridTeacher'];
        $timeslots   = $d['timeslots'];
        $schoolName  = $d['schoolName'];

        $allSlotNums = [];
        foreach ($timeslots as $ts) $allSlotNums[$ts['slot_number']] = $ts;
        ksort($allSlotNums);

        $html = '
        <style>
            body { font-family: dejavusans, sans-serif; font-size: 9pt; margin: 0; padding: 0; }
            h1 { font-size: 14pt; margin: 0 0 2px; text-align: center; }
            h2 { font-size: 12pt; margin: 0 0 2px; text-align: center; }
            .teacher-name {
                font-size: 11pt; font-weight: bold; text-align: center;
                margin: 5px 0 2px; padding: 4px; background: #f0f4f8;
            }
            h4 { font-size: 9pt; margin: 0 0 8px; text-align: center; color: #555; font-weight: normal; }
            .schedule-table { width: 100%; border-collapse: collapse; margin-bottom: 15px; }
            .schedule-table th {
                background: #1e3a5f; color: #fff; font-size: 8pt;
                padding: 5px 3px; text-align: center; border: 1px solid #555;
            }
            .schedule-table td {
                padding: 5px 3px; text-align: center;
                border: 1px solid #ccc; font-size: 8pt;
                vertical-align: middle;
            }
            .td-jam {
                background: #2d4f7c; color: #fff; font-weight: bold; font-size: 8pt;
            }
            .td-empty { background: #f9f9f9; }
            .summary-container { margin-top: 15px; width: 100%; }
            .summary-title { background: #1e3a5f; color: #fff; font-weight: bold; text-align: center; padding: 5px; font-size: 10pt; margin-bottom: 8px; }
            .summary-wrapper { width: 100%; overflow: hidden; }
            .summary-col { width: 48%; float: left; }
            .summary-col-right { width: 48%; float: right; }
            .summary-table { width: 100%; border-collapse: collapse; }
            .summary-table th { background: #2d4f7c; color: #fff; font-size: 8pt; padding: 4px; text-align: center; border: 1px solid #555; }
            .summary-table td { padding: 4px; font-size: 7.5pt; border: 1px solid #ccc; vertical-align: top; }
            .summary-table .class-cell { font-weight: bold; width: 25%; }
            .summary-table .subjects-cell { width: 55%; }
            .summary-table .hours-cell { text-align: center; width: 20%; }
            .clearfix { clear: both; }
        </style>';

        $isFirst = true;
        foreach ($teachers as $tid => $teacher) {
            if (!$isFirst) {
                $html .= '<div style="page-break-before:always"></div>';
            }
            $isFirst = false;

            // Hitung total jam dan ringkasan mengajar per kelas
            $totalHours = 0;
            $classSummary = [];
            
            if (isset($gridTeacher[$tid])) {
                foreach ($gridTeacher[$tid] as $day => $slots) {
                    foreach ($slots as $slotNum => $entry) {
                        if ($entry) {
                            $totalHours++;
                            $key = $entry['classroom_name'];
                            if (!isset($classSummary[$key])) {
                                $classSummary[$key] = [
                                    'class' => $entry['classroom_name'],
                                    'subjects' => [],
                                    'hours' => 0
                                ];
                            }
                            $classSummary[$key]['hours']++;
                            $classSummary[$key]['subjects'][$entry['subject_name']] = true;
                        }
                    }
                }
            }
            ksort($classSummary);

            $bgColor = ltrim($teacher['color'] ?: '#CCCCCC', '#');
            $fgColor = $this->getExcelTextColor($bgColor);

            $html .= '<h1>' . strtoupper(htmlspecialchars($schoolName)) . '</h1>';
            $html .= '<h2>JADWAL MENGAJAR GURU</h2>';
            $html .= '<div class="teacher-name" style="background:#' . $bgColor . ';color:#' . $fgColor . '">' . htmlspecialchars($teacher['name']) . ' [' . htmlspecialchars($teacher['short_code']) . '] — Total: ' . $totalHours . ' jam/minggu</div>';
            $html .= '<h4>Tahun Ajaran ' . htmlspecialchars($schedule['year_name']) . ' — Semester ' . htmlspecialchars($schedule['period_name']) . '</h4>';

            $colWidth = round(70 / count($activeDays), 1);
            $html .= '<table class="schedule-table"><thead><tr>';
            $html .= '<th style="width:15%">Jam</th>';
            foreach ($activeDays as $day) {
                $html .= '<th style="width:' . $colWidth . '%">' . strtoupper(substr($dayNames[$day], 0, 3)) . '</th>';
            }
            $html .= '</tr></thead><tbody>';

            foreach ($allSlotNums as $slotNum => $slotRef) {
                $isKbmAny = false;
                foreach ($activeDays as $day) {
                    $ts = array_filter($timeslots, fn($t) => $t['day']==$day && $t['slot_number']==$slotNum);
                    $ts = reset($ts);
                    if ($ts && $ts['slot_type']==='kbm') { $isKbmAny = true; break; }
                }

                if (!$isKbmAny) {
                    $icons = ['istirahat'=>'☕','upacara'=>'🚩','keagamaan'=>'🌙'];
                    $ico   = $icons[$slotRef['slot_type']] ?? '•';
                    $html .= '<tr style="background:#FFFBEB;color:#92400e;font-style:italic"><td class="td-jam">Jam ' . $slotNum . '<br><span style="font-size:7pt">' . substr($slotRef['start_time'], 0, 5) . '-' . substr($slotRef['end_time'], 0, 5) . '</span></td><td colspan="' . count($activeDays) . '">' . $ico . ' ' . esc($slotRef['label']) . '</td></tr>';
                    continue;
                }

                $html .= '<tr><td class="td-jam">Jam ' . $slotNum . '<br><span style="font-size:7pt">' . substr($slotRef['start_time'], 0, 5) . '-' . substr($slotRef['end_time'], 0, 5) . '</span></td>';

                foreach ($activeDays as $day) {
                    $entry = $gridTeacher[$tid][$day][$slotNum] ?? null;
                    if ($entry) {
                        $displayCode = $entry['subject_code'] ?: mb_substr($entry['subject_name'], 0, 10);
                        $html .= '<td style="background:#' . $bgColor . '15;font-weight:bold;font-size:8.5pt">'
                            . htmlspecialchars($entry['classroom_name'])
                            . '<br><span style="font-size:7pt;opacity:0.7">' . htmlspecialchars($displayCode) . '</span>'
                            . '</td>';
                    } else {
                        $html .= '<td class="td-empty">-</td>';
                    }
                }
                $html .= '</tr>';
            }
            $html .= '</tbody></table>';

            // Ringkasan Mengajar (2 kolom)
            if (!empty($classSummary)) {
                $summaryList = array_values($classSummary);
                $totalSummary = count($summaryList);
                $halfCount = ceil($totalSummary / 2);

                $html .= '<div class="summary-container">';
                $html .= '<div class="summary-title">RINGKASAN MENGAJAR</div>';
                $html .= '<div class="summary-wrapper">';

                // Kolom kiri
                $html .= '<div class="summary-col">';
                $html .= '<table class="summary-table"><thead><tr><th>Kelas</th><th>Mata Pelajaran</th><th>Jam</th></tr></thead><tbody>';
                for ($i = 0; $i < $halfCount; $i++) {
                    if (isset($summaryList[$i])) {
                        $item = $summaryList[$i];
                        $html .= '<tr>';
                        $html .= '<td class="class-cell" style="background:#' . $bgColor . '10;color:#' . $fgColor . '">' . htmlspecialchars($item['class']) . '</td>';
                        $html .= '<td class="subjects-cell">' . htmlspecialchars(implode(', ', array_keys($item['subjects']))) . '</td>';
                        $html .= '<td class="hours-cell">' . $item['hours'] . '</td>';
                        $html .= '</tr>';
                    }
                }
                $html .= '</tbody></table></div>';

                // Kolom kanan
                $html .= '<div class="summary-col-right">';
                $html .= '<table class="summary-table"><thead><tr><th>Kelas</th><th>Mata Pelajaran</th><th>Jam</th></tr></thead><tbody>';
                for ($i = $halfCount; $i < $totalSummary; $i++) {
                    if (isset($summaryList[$i])) {
                        $item = $summaryList[$i];
                        $html .= '<tr>';
                        $html .= '<td class="class-cell" style="background:#' . $bgColor . '10;color:#' . $fgColor . '">' . htmlspecialchars($item['class']) . '</td>';
                        $html .= '<td class="subjects-cell">' . htmlspecialchars(implode(', ', array_keys($item['subjects']))) . '</td>';
                        $html .= '<td class="hours-cell">' . $item['hours'] . '</td>';
                        $html .= '</tr>';
                    }
                }
                $html .= '</tbody></table></div>';

                $html .= '<div class="clearfix"></div>';
                $html .= '</div></div>';
            }
        }

        return $html;
    }

    // ── Helper: warna teks berdasarkan background ──────────────────────────
    private function getExcelTextColor($hexBg)
    {
        $hexBg = ltrim($hexBg, '#');
        if (strlen($hexBg) !== 6) return '000000';

        $r = hexdec(substr($hexBg, 0, 2));
        $g = hexdec(substr($hexBg, 2, 2));
        $b = hexdec(substr($hexBg, 4, 2));
        $luminance = (0.299 * $r + 0.587 * $g + 0.114 * $b) / 255;

        return $luminance > 0.5 ? '000000' : 'FFFFFF';
    }
}