<?php
/**
 * calendar_helper.php
 * Helper untuk modul Kalender Pendidikan:
 * - Nama bulan & hari dalam Bahasa Indonesia
 * - Membentuk matrix tanggal per bulan (Senin - Minggu) untuk grid cetak
 * - Menghitung rekap hari efektif per bulan
 */

if (! function_exists('cal_indo_month')) {
    function cal_indo_month(int $month): string
    {
        $names = [
            1 => 'Januari', 2 => 'Februari', 3 => 'Maret', 4 => 'April',
            5 => 'Mei', 6 => 'Juni', 7 => 'Juli', 8 => 'Agustus',
            9 => 'September', 10 => 'Oktober', 11 => 'November', 12 => 'Desember',
        ];

        return $names[$month] ?? '';
    }
}

if (! function_exists('cal_indo_day_short')) {
    /**
     * Header hari, urutan Minggu - Sabtu (standar kalender umum Indonesia)
     * Kolom 0 = Minggu (dow 7), kolom 1-6 = Senin-Sabtu (dow 1-6)
     */
    function cal_indo_day_short(int $colIndex): string
    {
        // colIndex 0 = Minggu, 1 = Senin, ..., 6 = Sabtu
        $names = ['Min', 'Sen', 'Sel', 'Rab', 'Kam', 'Jum', 'Sab'];
        return $names[$colIndex] ?? '';
    }
}

if (! function_exists('cal_month_matrix')) {
    /**
     * Membentuk matrix tanggal 1 bulan, mulai MINGGU, untuk ditampilkan
     * sebagai grid 7 kolom x (5 atau 6) baris.
     * Kolom 0 = Minggu, kolom 1 = Senin, ..., kolom 6 = Sabtu
     *
     * @return array<int, array<int, array{date:?string, day:?int, col:int}>>
     */
    function cal_month_matrix(int $year, int $month): array
    {
        $firstTimestamp = mktime(0, 0, 0, $month, 1, $year);
        $daysInMonth    = (int) date('t', $firstTimestamp);

        // date('w'): 0=Minggu, 1=Senin, ..., 6=Sabtu — pas untuk kolom kita
        $firstDow = (int) date('w', $firstTimestamp);

        $weeks = [];
        $week  = [];

        // Isi kolom kosong sebelum tanggal 1
        for ($i = 0; $i < $firstDow; $i++) {
            $week[] = ['date' => null, 'day' => null, 'col' => $i];
        }

        for ($d = 1; $d <= $daysInMonth; $d++) {
            $col    = (int) date('w', mktime(0, 0, 0, $month, $d, $year));
            $week[] = [
                'date' => sprintf('%04d-%02d-%02d', $year, $month, $d),
                'day'  => $d,
                'col'  => $col,
            ];

            if (count($week) === 7) {
                $weeks[] = $week;
                $week    = [];
            }
        }

        // Lengkapi baris terakhir
        if (! empty($week)) {
            while (count($week) < 7) {
                $week[] = ['date' => null, 'day' => null, 'col' => count($week)];
            }
            $weeks[] = $week;
        }

        return $weeks;
    }
}

if (! function_exists('cal_build_day_map')) {
    /**
     * Membentuk peta tanggal => kategori dari daftar kegiatan.
     * Jika ada kegiatan beririsan pada tanggal yang sama, kategori
     * dengan is_libur = 1 diprioritaskan (libur menang atas kegiatan biasa).
     *
     * @param array $events hasil CalendarEventModel::getByYear()
     * @return array<string, array{color:string, code:string, title:string, is_libur:int}>
     */
    function cal_build_day_map(array $events): array
    {
        $map = [];

        foreach ($events as $e) {
            $start = strtotime($e['start_date']);
            $end   = strtotime($e['end_date']);

            for ($t = $start; $t <= $end; $t = strtotime('+1 day', $t)) {
                $key = date('Y-m-d', $t);

                if (isset($map[$key]) && (int) $map[$key]['is_libur'] === 1 && (int) $e['is_libur'] === 0) {
                    // Tanggal sudah ditandai libur, jangan ditimpa kegiatan biasa
                    continue;
                }

                $map[$key] = [
                    'color'    => $e['color'],
                    'code'     => $e['category_code'],
                    'title'    => $e['title'],
                    'is_libur' => (int) $e['is_libur'],
                ];
            }
        }

        return $map;
    }
}

if (! function_exists('cal_academic_year_months')) {
    /**
     * Mengembalikan array 12 bulan (Juli - Juni) berdasarkan nama tahun ajaran
     * dengan format "2025/2026".
     *
     * @return array<int, array{year:int, month:int}>
     */
    function cal_academic_year_months(string $yearName): array
    {
        $parts = explode('/', $yearName);
        $y1    = (int) ($parts[0] ?? date('Y'));
        $y2    = (int) ($parts[1] ?? ($y1 + 1));

        $months = [];
        for ($m = 7; $m <= 12; $m++) {
            $months[] = ['year' => $y1, 'month' => $m];
        }
        for ($m = 1; $m <= 6; $m++) {
            $months[] = ['year' => $y2, 'month' => $m];
        }

        return $months;
    }
}

if (! function_exists('cal_effective_days_per_month')) {
    /**
     * Hitung rekap jumlah hari per bulan: total hari, hari libur (Sabtu/Minggu
     * atau kategori is_libur), dan hari efektif belajar.
     *
     * @param array $months  hasil cal_academic_year_months()
     * @param array $dayMap  hasil cal_build_day_map()
     * @param bool  $sabtuLibur  true jika Sabtu dihitung libur (5 hari sekolah)
     * @param string|null $startDate  tanggal mulai tahun ajaran (YYYY-MM-DD)
     * @param string|null $endDate  tanggal akhir tahun ajaran (YYYY-MM-DD)
     *
     * @return array<int, array{label:string, total:int, libur:int, efektif:int}>
     */
    function cal_effective_days_per_month(array $months, array $dayMap, bool $sabtuLibur = false, ?string $startDate = null, ?string $endDate = null): array
    {
        $rekap = [];

        foreach ($months as $m) {
            $daysInMonth = (int) date('t', mktime(0, 0, 0, $m['month'], 1, $m['year']));
            $libur       = 0;

            for ($d = 1; $d <= $daysInMonth; $d++) {
                $key = sprintf('%04d-%02d-%02d', $m['year'], $m['month'], $d);
                $dow = (int) date('N', mktime(0, 0, 0, $m['month'], $d, $m['year'])); // 6=Sabtu, 7=Minggu

                $isWeekendLibur = ($dow === 7) || ($sabtuLibur && $dow === 6);
                $isEventLibur   = isset($dayMap[$key]) && (int) $dayMap[$key]['is_libur'] === 1;
                $isOutsideYear  = ($startDate !== null && $key < $startDate) || ($endDate !== null && $key > $endDate);

                if ($isWeekendLibur || $isEventLibur || $isOutsideYear) {
                    $libur++;
                }
            }

            $rekap[] = [
                'label'   => cal_indo_month($m['month']) . ' ' . $m['year'],
                'total'   => $daysInMonth,
                'libur'   => $libur,
                'efektif' => $daysInMonth - $libur,
            ];
        }

        return $rekap;
    }
}