<?php defined('BASEPATH') OR exit('No direct script access allowed');

/**
 * Kalender_model — RT Management System
 *
 * Fitur:
 *  1. Hari libur nasional  (API libur.deno.dev, cache 24 jam)
 *  2. Kalender Jawa        (weton / pasaran / neptu, hitung lokal)
 *  3. Jadwal pribadi warga (CRUD, tabel jadwal_warga)
 *  4. Kegiatan RT          (CRUD admin, tabel kegiatan_rt)
 *  5. Helper gabungan      (untuk modal detail tanggal via AJAX)
 *
 *  CATATAN: Tidak menggunakan ekstensi Calendar PHP (cal_days_in_month,
 *  gregoriantojd, dsb.) agar kompatibel di semua hosting shared.
 */
class Kalender_model extends CI_Model
{
    // ==========================================================
    //  1. HARI LIBUR NASIONAL
    // ==========================================================

    public function get_hari_libur($tahun, $bulan)
    {
        $dir = APPPATH . 'cache/';
        if (!is_dir($dir)) mkdir($dir, 0755, true);

        $f = $dir . 'libur_' . $tahun . '_' . $bulan . '.json';

        if (file_exists($f) && (time() - filemtime($f)) < 86400) {
            $d = json_decode(file_get_contents($f), true);
            if (is_array($d)) return $d;
        }

        $ch = curl_init('https://libur.deno.dev/api?year='.$tahun.'&month='.$bulan);
        curl_setopt_array($ch, [
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_SSL_VERIFYPEER => false,
            CURLOPT_TIMEOUT        => 8,
            CURLOPT_USERAGENT      => 'RT-App/1.0',
        ]);
        $res = curl_exec($ch);
        // curl_close($ch);

        $data = ($res) ? json_decode($res, true) : [];
        if (!is_array($data)) $data = [];
        file_put_contents($f, json_encode($data));
        return $data;
    }

    // ==========================================================
    //  2. KALENDER JAWA
    // ==========================================================

    /**
     * Hitung pasaran Jawa.
     * Referensi: 1 Januari 2000 = Sabtu PAHING (index 1)
     * Siklus 5-hari: 0=Legi, 1=Pahing, 2=Pon, 3=Wage, 4=Kliwon
     * Neptu       :  Legi=5  Pahing=9  Pon=7  Wage=4  Kliwon=8
     */
    public function get_pasaran($tanggal_str)
    {
        $list  = ['Legi','Pahing','Pon','Wage','Kliwon'];
        $neptu = [5, 9, 7, 4, 8];

        $ref  = mktime(0,0,0,1,1,2000);        // Sabtu Pahing = idx 1
        $diff = (int)((strtotime($tanggal_str) - $ref) / 86400);
        $idx  = (($diff % 5) + 5 + 1) % 5;    // +1 offset Pahing

        return ['nama' => $list[$idx], 'neptu' => $neptu[$idx], 'index' => $idx];
    }

    /**
     * Hitung weton lengkap.
     * Neptu hari: Ahad=5 Senin=4 Selasa=3 Rabu=7 Kamis=8 Jumat=6 Sabtu=9
     */
    public function get_weton($tanggal_str)
    {
        $hari  = ['Ahad','Senin','Selasa','Rabu','Kamis','Jumat','Sabtu'];
        $neptu = [5, 4, 3, 7, 8, 6, 9];

        $dow     = (int)date('w', strtotime($tanggal_str));
        $pasaran = $this->get_pasaran($tanggal_str);

        return [
            'hari'          => $hari[$dow],
            'neptu_hari'    => $neptu[$dow],
            'pasaran'       => $pasaran['nama'],
            'neptu_pasaran' => $pasaran['neptu'],
            'neptu_total'   => $neptu[$dow] + $pasaran['neptu'],
            'weton'         => $hari[$dow] . ' ' . $pasaran['nama'],
        ];
    }

    /**
     * Konversi Gregorian ke Julian Day Number (murni PHP, tanpa ekstensi).
     * Algoritma: Jean Meeus, "Astronomical Algorithms"
     */
    private function _gregorian_to_jd($bulan, $hari, $tahun)
    {
        if ($bulan <= 2) {
            $tahun--;
            $bulan += 12;
        }
        $A = (int)($tahun / 100);
        $B = 2 - $A + (int)($A / 4);
        return (int)(365.25 * ($tahun + 4716))
             + (int)(30.6001 * ($bulan + 1))
             + $hari + $B - 1524;
    }

    /**
     * Tentukan nama bulan Jawa (Hijriyah Jawa) dari tanggal Gregorian.
     * Menggunakan perhitungan JDN murni tanpa ekstensi Calendar PHP.
     */
    private function _bulan_jawa($bulan, $tahun)
    {
        $bj = ['Sura','Sapar','Mulud','Bakda Mulud',
               'Jumadil Awal','Jumadil Akhir','Rejeb','Ruwah',
               'Pasa','Sawal','Dulkaidah','Besar'];

        $jd     = $this->_gregorian_to_jd($bulan, 15, $tahun);
        $delta  = $jd - 1948440;
        $h_mon  = (int)fmod(floor(($delta * 12) / 354.367) + 1, 12);
        $h_mon  = max(1, min(12, $h_mon));
        return $bj[$h_mon - 1];
    }

    // ==========================================================
    //  3. GRID KALENDER BULANAN
    // ==========================================================

    public function get_kalender_bulanan($tahun, $bulan)
    {
        $libur_raw = $this->get_hari_libur($tahun, $bulan);
        $libur_map = [];
        foreach ($libur_raw as $h) {
            $libur_map[(int)date('j', strtotime($h['date']))] = $h['name'];
        }

        $bln_nm = ['','Januari','Februari','Maret','April','Mei','Juni',
                   'Juli','Agustus','September','Oktober','November','Desember'];

        $jml_hari  = (int)date('t', mktime(0,0,0,$bulan,1,$tahun));
        $hari_awal = (int)date('w', mktime(0,0,0,$bulan,1,$tahun));
        $today     = date('Y-m-d');
        $kalender  = [];
        $minggu    = [];

        for ($i = 0; $i < $hari_awal; $i++) $minggu[] = null;

        for ($tgl = 1; $tgl <= $jml_hari; $tgl++) {
            $ds  = sprintf('%04d-%02d-%02d', $tahun, $bulan, $tgl);
            $dow = (int)date('w', mktime(0,0,0,$bulan,$tgl,$tahun));
            $wt  = $this->get_weton($ds);

            $minggu[] = [
                'tanggal'   => $tgl,
                'date_str'  => $ds,
                'hari'      => $wt['hari'],
                'pasaran'   => $wt['pasaran'],
                'weton'     => $wt['weton'],
                'neptu'     => $wt['neptu_total'],
                'is_minggu' => ($dow === 0),
                'is_sabtu'  => ($dow === 6),
                'libur'     => $libur_map[$tgl] ?? null,
                'is_today'  => ($ds === $today),
            ];

            if (count($minggu) === 7) { $kalender[] = $minggu; $minggu = []; }
        }

        if (!empty($minggu)) {
            while (count($minggu) < 7) $minggu[] = null;
            $kalender[] = $minggu;
        }

        return [
            'minggu_grid' => $kalender,
            'bulan_nama'  => $bln_nm[$bulan],
            'bulan_jawa'  => $this->_bulan_jawa($bulan, $tahun),
            'tahun'       => $tahun,
            'bulan'       => $bulan,
            'jumlah_hari' => $jml_hari,
            'libur_map'   => $libur_map,
        ];
    }

    // ==========================================================
    //  4. JADWAL PRIBADI WARGA
    // ==========================================================

    /** Jadwal warga 1 bulan, dikelompokkan per nomor hari */
    public function get_jadwal_warga($warga_id, $tahun, $bulan)
    {
        $awal  = sprintf('%04d-%02d-01', $tahun, $bulan);
        $akhir = sprintf('%04d-%02d-%02d', $tahun, $bulan,
                         (int)date('t', mktime(0,0,0,$bulan,1,$tahun)));

        $rows = $this->db
            ->where('warga_id', (int)$warga_id)
            ->where('tanggal >=', $awal)
            ->where('tanggal <=', $akhir)
            ->order_by('tanggal,waktu_mulai', 'ASC')
            ->get('jadwal_warga')->result();

        $map = [];
        foreach ($rows as $r) {
            $map[(int)date('j', strtotime($r->tanggal))][] = $r;
        }
        return $map;
    }

    /** Jadwal warga 1 tanggal spesifik */
    public function get_jadwal_by_tanggal($warga_id, $tanggal_str)
    {
        return $this->db
            ->where('warga_id', (int)$warga_id)
            ->where('tanggal', $tanggal_str)
            ->order_by('waktu_mulai', 'ASC')
            ->get('jadwal_warga')->result();
    }

    /** Ambil 1 jadwal by ID (untuk form edit) */
    public function get_jadwal_by_id($id, $warga_id)
    {
        return $this->db
            ->where('id', (int)$id)
            ->where('warga_id', (int)$warga_id)
            ->get('jadwal_warga')->row();
    }

    public function simpan_jadwal(array $data)
    {
        return $this->db->insert('jadwal_warga', $data);
    }

    public function update_jadwal($id, $warga_id, array $data)
    {
        return $this->db
            ->where('id', (int)$id)
            ->where('warga_id', (int)$warga_id)
            ->update('jadwal_warga', $data);
    }

    public function hapus_jadwal($id, $warga_id)
    {
        return $this->db
            ->where('id', (int)$id)
            ->where('warga_id', (int)$warga_id)
            ->delete('jadwal_warga');
    }

    public function toggle_selesai($id, $warga_id)
    {
        $row = $this->db
            ->select('is_selesai')
            ->where('id', (int)$id)
            ->where('warga_id', (int)$warga_id)
            ->get('jadwal_warga')->row();
        if (!$row) return false;

        return $this->db
            ->where('id', (int)$id)
            ->where('warga_id', (int)$warga_id)
            ->update('jadwal_warga', ['is_selesai' => ($row->is_selesai ? 0 : 1)]);
    }

    /** Jadwal mendatang untuk widget dashboard */
    public function get_jadwal_mendatang($warga_id, $limit = 5)
    {
        return $this->db
            ->where('warga_id', (int)$warga_id)
            ->where('tanggal >=', date('Y-m-d'))
            ->where('is_selesai', 0)
            ->order_by('tanggal,waktu_mulai', 'ASC')
            ->limit((int)$limit)
            ->get('jadwal_warga')->result();
    }

    /** Hitung jadwal aktif bulan ini (untuk badge sidebar) */
    public function count_jadwal_bulan_ini($warga_id)
    {
        return $this->db
            ->where('warga_id', (int)$warga_id)
            ->where('tanggal >=', date('Y-m-01'))
            ->where('tanggal <=', date('Y-m-t'))
            ->where('is_selesai', 0)
            ->count_all_results('jadwal_warga');
    }

    // ==========================================================
    //  5. KEGIATAN RT
    // ==========================================================

    /** Kegiatan RT 1 bulan, dikelompokkan per nomor hari */
    public function get_kegiatan_rt($tahun, $bulan)
    {
        $awal  = sprintf('%04d-%02d-01', $tahun, $bulan);
        $akhir = sprintf('%04d-%02d-%02d', $tahun, $bulan,
                         (int)date('t', mktime(0,0,0,$bulan,1,$tahun)));

        $rows = $this->db
            ->where('tanggal >=', $awal)
            ->where('tanggal <=', $akhir)
            ->order_by('tanggal,waktu_mulai', 'ASC')
            ->get('kegiatan_rt')->result();

        $map = [];
        foreach ($rows as $r) {
            $map[(int)date('j', strtotime($r->tanggal))][] = $r;
        }
        return $map;
    }

    /** Kegiatan RT 1 tanggal spesifik */
    public function get_kegiatan_by_tanggal($tanggal_str)
    {
        return $this->db
            ->where('tanggal', $tanggal_str)
            ->order_by('waktu_mulai', 'ASC')
            ->get('kegiatan_rt')->result();
    }

    public function get_kegiatan_by_id($id)
    {
        return $this->db->get_where('kegiatan_rt', ['id' => (int)$id])->row();
    }

    public function simpan_kegiatan(array $data)
    {
        return $this->db->insert('kegiatan_rt', $data);
    }

    public function update_kegiatan($id, array $data)
    {
        return $this->db->where('id', (int)$id)->update('kegiatan_rt', $data);
    }

    public function hapus_kegiatan($id)
    {
        return $this->db->delete('kegiatan_rt', ['id' => (int)$id]);
    }

    /** Kegiatan RT mendatang untuk widget dashboard */
    public function get_kegiatan_mendatang($limit = 5)
    {
        return $this->db
            ->where('tanggal >=', date('Y-m-d'))
            ->order_by('tanggal,waktu_mulai', 'ASC')
            ->limit((int)$limit)
            ->get('kegiatan_rt')->result();
    }

    // ==========================================================
    //  6. HELPER GABUNGAN
    // ==========================================================

    /** Semua data 1 tanggal: weton + jadwal warga + kegiatan RT */
    public function get_detail_tanggal($tanggal_str, $warga_id)
    {
        return [
            'weton'    => $this->get_weton($tanggal_str),
            'jadwal'   => $this->get_jadwal_by_tanggal($warga_id, $tanggal_str),
            'kegiatan' => $this->get_kegiatan_by_tanggal($tanggal_str),
        ];
    }
}