<?php

namespace App\Controllers\Guru\Traits;

use App\Models\TeacherModel;
use App\Models\LearningDeviceModel;
use App\Models\LearningDeviceTpModel;
use App\Models\LearningDeviceModulModel;
use App\Models\LearningDeviceKktpModel;
use App\Models\SchoolSettingModel;
use Config\Database;

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

    protected function getTeacher()
    {
        $teacherModel = new TeacherModel();
        return $teacherModel->where('user_id', session()->get('user_id'))->first();
    }

    protected function deducePhase(string $gradeName): string
    {
        $name = trim(strtoupper($gradeName));
        if ($name === 'I' || $name === 'II' || $name === '1' || $name === '2') {
            return 'A';
        }
        if ($name === 'III' || $name === 'IV' || $name === '3' || $name === '4') {
            return 'B';
        }
        if ($name === 'V' || $name === 'VI' || $name === '5' || $name === '6') {
            return 'C';
        }
        if ($name === 'VII' || $name === 'VIII' || $name === 'IX' || $name === '7' || $name === '8' || $name === '9') {
            return 'D';
        }
        if ($name === 'X' || $name === '10') {
            return 'E';
        }
        if ($name === 'XI' || $name === 'XII' || $name === '11' || $name === '12') {
            return 'F';
        }
        return 'D'; // default
    }

    protected function calculateEffectiveWeeks(array $activePeriod): int
    {
        if (empty($activePeriod['start_date']) || empty($activePeriod['end_date'])) {
            return 18;
        }

        try {
            $start = new \DateTime($activePeriod['start_date']);
            $end = new \DateTime($activePeriod['end_date']);

            $db = Database::connect();
            $liburEvents = $db->table('calendar_events ce')
                ->select('ce.start_date, ce.end_date')
                ->join('calendar_categories cc', 'cc.id = ce.category_id')
                ->where('ce.academic_year_id', $activePeriod['academic_year_id'])
                ->where('cc.is_libur', 1)
                ->where('ce.deleted_at', null)
                ->get()->getResultArray();

            $liburDays = [];
            foreach ($liburEvents as $ev) {
                $evStart = new \DateTime($ev['start_date']);
                $evEnd = new \DateTime($ev['end_date']);
                $currEv = clone $evStart;
                while ($currEv <= $evEnd) {
                    $liburDays[$currEv->format('Y-m-d')] = true;
                    $currEv->modify('+1 day');
                }
            }

            $effectiveWeeks = 0;
            $current = clone $start;

            while ($current <= $end) {
                $holidayCount = 0;
                for ($i = 0; $i < 7; $i++) {
                    $dateStr = $current->format('Y-m-d');
                    $dayOfWeek = (int)$current->format('w');
                    if ($dayOfWeek === 0 || isset($liburDays[$dateStr])) {
                        $holidayCount++;
                    }
                    $current->modify('+1 day');
                    if ($current > $end) break;
                }
                if ($holidayCount < 4) {
                    $effectiveWeeks++;
                }
            }
            return $effectiveWeeks > 0 ? $effectiveWeeks : 18;
        } catch (\Throwable $e) {
            return 18;
        }
    }

    protected function calculateRpeFromKaldik($id): ?array
    {
        $db = Database::connect();
        $deviceModel = new LearningDeviceModel();
        $device = $deviceModel->getDetail($id);
        if (!$device) {
            return null;
        }

        $academicYearId = $device['academic_year_id'];

        $liburEvents = $db->table('calendar_events ce')
            ->select('ce.title, ce.start_date, ce.end_date, cc.name as category_name, cc.is_libur')
            ->join('calendar_categories cc', 'cc.id = ce.category_id')
            ->where('ce.academic_year_id', $academicYearId)
            ->where('ce.deleted_at', null)
            ->get()->getResultArray();

        $liburDaysMap = [];
        foreach ($liburEvents as $ev) {
            if ($ev['is_libur'] == 1) {
                $start = new \DateTime($ev['start_date']);
                $end = new \DateTime($ev['end_date']);
                $curr = clone $start;
                while ($curr <= $end) {
                    $liburDaysMap[$curr->format('Y-m-d')] = $ev['title'];
                    $curr->modify('+1 day');
                }
            }
        }

        $sabtuLibur = false;
        $setting = $db->table('calendar_settings')->where('key', 'sabtu_libur')->get()->getRowArray();
        if ($setting && isset($setting['value']) && (int)$setting['value'] === 1) {
            $sabtuLibur = true;
        }

        $academicYear = $db->table('academic_years')->where('id', $academicYearId)->get()->getRowArray();
        $startYear = 2026;
        $endYear = 2027;
        if ($academicYear && !empty($academicYear['start_date'])) {
            $startYear = intval((new \DateTime($academicYear['start_date']))->format('Y'));
        }
        if ($academicYear && !empty($academicYear['end_date'])) {
            $endYear = intval((new \DateTime($academicYear['end_date']))->format('Y'));
        }

        $processSemester = function ($months, $year) use ($liburDaysMap, $sabtuLibur, $academicYear) {
            $data = [];
            foreach ($months as $mNum => $mName) {
                $monthStartStr = sprintf('%04d-%02d-01', $year, $mNum);
                $monthStart = new \DateTime($monthStartStr);
                $monthEnd = clone $monthStart;
                $monthEnd->modify('last day of this month');

                $weeks = [];
                $currentWeekIndex = 0;
                $current = clone $monthStart;

                while ($current <= $monthEnd) {
                    $dayOfWeek = (int)$current->format('w');
                    if ($dayOfWeek === 1 && $current > $monthStart) {
                        $currentWeekIndex++;
                    }
                    $weeks[$currentWeekIndex][] = clone $current;
                    $current->modify('+1 day');
                }

                $totalWeeks = count($weeks);
                $effectiveWeeks = 0;
                $nonEffectiveWeeks = 0;
                $notes = [];
                $weekStatuses = [];

                foreach ($weeks as $wIdx => $days) {
                    $holidayCount = 0;
                    $weekNotes = [];
                    $totalDaysInWeek = count($days);

                    foreach ($days as $day) {
                        $dateStr = $day->format('Y-m-d');
                        $dayOfWeek = (int)$day->format('w');

                        $isHoliday = false;

                        $academicYearStart = !empty($academicYear['start_date']) ? new \DateTime($academicYear['start_date']) : null;
                        $academicYearEnd = !empty($academicYear['end_date']) ? new \DateTime($academicYear['end_date']) : null;

                        if ($academicYearStart && $day < $academicYearStart) {
                            $isHoliday = true;
                            $weekNotes[] = 'Sebelum Awal Tahun Pelajaran';
                        } elseif ($academicYearEnd && $day > $academicYearEnd) {
                            $isHoliday = true;
                            $weekNotes[] = 'Setelah Akhir Tahun Pelajaran';
                        } elseif ($dayOfWeek === 0) {
                            $isHoliday = true;
                        } elseif ($dayOfWeek === 6 && $sabtuLibur) {
                            $isHoliday = true;
                        } elseif (isset($liburDaysMap[$dateStr])) {
                            $isHoliday = true;
                            $weekNotes[] = $liburDaysMap[$dateStr];
                        }

                        if ($isHoliday) {
                            $holidayCount++;
                        }
                    }

                    $isEffective = true;
                    if ($holidayCount >= 4 || ($totalDaysInWeek < 7 && $holidayCount >= ceil($totalDaysInWeek / 2))) {
                        $nonEffectiveWeeks++;
                        $isEffective = false;
                        if (!empty($weekNotes)) {
                            $notes = array_merge($notes, $weekNotes);
                        }
                    } else {
                        $effectiveWeeks++;
                    }
                    $weekStatuses[$wIdx + 1] = $isEffective;
                }

                for ($w = 1; $w <= 5; $w++) {
                    if (!isset($weekStatuses[$w])) {
                        $weekStatuses[$w] = false;
                    }
                }

                $uniqueNotes = array_values(array_unique(array_filter($notes)));
                $noteText = implode(', ', $uniqueNotes);

                if ($mNum == 12 && empty($noteText)) {
                    $noteText = 'Libur Semester 1';
                }
                if ($mNum == 6 && empty($noteText)) {
                    $noteText = 'Libur Akhir Tahun Pelajaran';
                }

                $data[$mNum] = [
                    'total_weeks'         => $totalWeeks,
                    'effective_weeks'     => $effectiveWeeks,
                    'non_effective_weeks' => $nonEffectiveWeeks,
                    'note'                => $noteText,
                    'week_statuses'       => $weekStatuses
                ];
            }
            return $data;
        };

        $monthsS1 = [7 => 'Juli', 8 => 'Agustus', 9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember'];
        $monthsS2 = [1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April', 5 => 'Mei', 6 => 'Juni'];

        return [
            'sem1' => $processSemester($monthsS1, $startYear),
            'sem2' => $processSemester($monthsS2, $endYear)
        ];
    }

    protected function generateDaftarPustaka(array $device, ?array $settings): string
    {
        $schoolName = $settings['school_name'] ?? 'Sekolah';
        $subjectName = $device['subject_name'] ?? '';
        $tahunAjaran = $device['academic_year_name'] ?? date('Y') . '/' . (date('Y') + 1);

        $pustaka = [];
        $pustaka[] = "Kemendikdasmen RI. (2025). Permendikdasmen No. 10 Tahun 2025 tentang Profil Lulusan. Jakarta: Kemendikdasmen.";
        if ($device['school_type'] === 'madrasah') {
            $pustaka[] = "Kemenag RI. (2025). KMA No. 1503 Tahun 2025 tentang Pedoman Implementasi Kurikulum Madrasah. Jakarta: Kemenag RI.";
            $pustaka[] = "Kemenag RI. (2025). SK Dirjen Pendis No. 6077 Tahun 2025 tentang Panduan Kurikulum Berbasis Cinta (KBC). Jakarta: Kemenag RI.";
        }
        $pustaka[] = "Kementerian Agama RI. (2020). Buku Siswa " . $subjectName . " Kelas " . $device['grade_name'] . " MTs. Jakarta: Direktorat Jenderal Pendidikan Islam.";
        $pustaka[] = "Buku Guru " . $subjectName . " Kelas " . $device['grade_name'] . " Kurikulum Merdeka. Jakarta: Kemendikbudristek.";
        $pustaka[] = "Al-Qur'an Al-Karim (Mushaf Standar Indonesia, Kemenag RI).";

        return implode("\n", $pustaka);
    }

    protected function hitungPertemuanDariPromes(int $deviceId, array $chapterTps): int
    {
        if (empty($chapterTps)) return 0;

        $tpIds = array_column($chapterTps, 'id');
        if (empty($tpIds)) return 0;

        $db = Database::connect();
        $promes = $db->table('learning_device_promes')
            ->where('learning_device_id', $deviceId)
            ->whereIn('tp_id', $tpIds)
            ->get()->getResultArray();

        if (empty($promes)) return 0;

        $weeks = [];
        foreach ($promes as $p) {
            $key = $p['month'] . '-' . $p['week_number'];
            $weeks[$key] = true;
        }

        return count($weeks);
    }

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

        $deviceModel = new LearningDeviceModel();
        $device = $deviceModel->getDetail($id, $teacher['user_id']);
        if (!$device) {
            return redirect()->to('/guru/learning-devices')->with('error', 'Dokumen tidak ditemukan atau Anda tidak memiliki akses!');
        }

        return $device;
    }

    protected function getDeviceOrJsonError($id)
    {
        $teacher = $this->getTeacher();
        if (!$teacher) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Sesi berakhir, silakan login kembali.']);
        }

        $deviceModel = new LearningDeviceModel();
        $device = $deviceModel->getDetail($id, $teacher['user_id']);
        if (!$device) {
            return $this->response->setJSON(['status' => 'error', 'message' => 'Dokumen tidak ditemukan.']);
        }

        return $device;
    }
}
