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

class Cronjob extends CI_Controller {

    public function __construct()
    {
        parent::__construct();
        $this->load->database();

        // ONLY CLI ACCESS
        // if (!$this->input->is_cli_request()) {
        //     exit('No direct access allowed');
        // }
    }

    public function generate_insight()
    {
        $period = date('Y-m');

        // =====================================================
        // 🔥 REPLACE MODE (hapus data lama dulu)
        // =====================================================
        $this->db->where('period', $period);
        $this->db->delete('ai_insights');

        // =====================================================
        // 1. FINANCE - OVERDUE INVOICE
        // =====================================================
        $overdue = $this->db->query("
            SELECT COUNT(*) as total
            FROM invoices
            WHERE status != 'paid'
            AND jatuh_tempo < CURDATE()
            AND deleted_at IS NULL
        ")->row()->total;

        if ($overdue > 0) {
            $this->db->insert('ai_insights', [
                'type' => 'finance',
                'severity' => 'warning',
                'message' => "$overdue invoice sudah melewati jatuh tempo",
                'meta' => json_encode([
                    'overdue_count' => (int)$overdue
                ]),
                'period' => $period
            ]);
        }

        // =====================================================
        // 2. FINANCE - CASHFLOW BULAN INI
        // =====================================================
        $cash = $this->db->query("
            SELECT COALESCE(SUM(jd.debit),0) as cash_in
            FROM journal_details jd
            JOIN journals j ON j.id = jd.journal_id
            WHERE MONTH(j.tanggal) = MONTH(CURDATE())
            AND YEAR(j.tanggal) = YEAR(CURDATE())
        ")->row()->cash_in;

        if ($cash > 0) {
            $this->db->insert('ai_insights', [
                'type' => 'finance',
                'severity' => ($cash > 10000000) ? 'info' : 'warning',
                'message' => "Cashflow bulan ini Rp " . number_format($cash),
                'meta' => json_encode([
                    'cash_in' => (float)$cash
                ]),
                'period' => $period
            ]);
        }

        // =====================================================
        // 3. STOCK - KRITIS
        // =====================================================
        $stocks = $this->db->query("
            SELECT 
                i.kode_id,
                k.nama_barang,
                SUM(i.stok) as total_stok,
                k.limit_stock
            FROM items i
            JOIN kode_barang k ON k.id = i.kode_id
            GROUP BY i.kode_id, k.nama_barang, k.limit_stock
            HAVING total_stok <= k.limit_stock
        ")->result();

        foreach ($stocks as $s) {
            $this->db->insert('ai_insights', [
                'type' => 'stock',
                'severity' => 'critical',
                'message' => "Stok {$s->nama_barang} kritis ({$s->total_stok})",
                'meta' => json_encode([
                    'kode_id' => $s->kode_id,
                    'item' => $s->nama_barang,
                    'stok' => (int)$s->total_stok,
                    'limit' => (int)$s->limit_stock
                ]),
                'period' => $period
            ]);
        }

        // =====================================================
        // 4. CUSTOMER - PAYMENT RISK
        // =====================================================
        $lateCustomers = $this->db->query("
            SELECT 
                c.nama,
                COUNT(i.id) as total_invoice
            FROM invoices i
            JOIN customers c ON c.id = i.customer_id
            WHERE i.status != 'paid'
            AND i.jatuh_tempo < CURDATE()
            GROUP BY i.customer_id
            HAVING total_invoice > 2
        ")->result();

        foreach ($lateCustomers as $c) {
            $this->db->insert('ai_insights', [
                'type' => 'customer',
                'severity' => 'warning',
                'message' => "Customer {$c->nama} memiliki {$c->total_invoice} invoice overdue",
                'meta' => json_encode([
                    'customer' => $c->nama,
                    'overdue_invoice' => (int)$c->total_invoice
                ]),
                'period' => $period
            ]);
        }

        // =====================================================
        // RESPONSE
        // =====================================================
        echo json_encode([
            'status' => true,
            'message' => 'AI Insight generated (REPLACE MODE)',
            'period' => $period
        ]);
    }

    // =====================================================
    // CRONJOB UNTUK LIHAT KEHADIRAN SELAMA 1 BULAN
    // =====================================================

    // | Kriteria               |         Pengurangan |
    // | ---------------------- | ------------------: |
    // | Alpha                  |     -20 poin / hari |
    // | Terlambat              |  -2 poin / kejadian |
    // | Izin (permit)          |      -1 poin / hari |
    // | Akumulasi telat        |  -1 poin / 60 menit |
    // | Akumulasi pulang cepat | -1 poin / 120 menit |

    public function generateMonthlyAttendance()
    {
        $month = date('Y-m-01');

        $startDate = date('Y-m-01', strtotime($month));
        $endDate   = date('Y-m-t', strtotime($month));

        $employees = $this->db
            ->where('is_active', 1)
            ->get('k_employees')
            ->result();

        $processed = 0;

        $this->db->trans_begin();

        try {

            foreach ($employees as $employee) {
                
                // Total Hari Kerja
                $schedule = $this->db->query("
                    SELECT
                        COUNT(*) AS total_hari_kerja
                    FROM k_employee_shift_schedules
                    WHERE employee_id = ?
                    AND status IN ('published','done')
                    AND schedule_date BETWEEN ? AND ?
                ", array(
                    $employee->id,
                    $startDate,
                    $endDate
                ))->row();

                $total_hari_kerja = (int) $schedule->total_hari_kerja;

                // Rekap Absensi
                $attendance = $this->db->query("
                    SELECT

                        COALESCE(SUM(attendance_status='present'),0) AS total_present,
                        COALESCE(SUM(attendance_status='late'),0) AS total_late,
                        COALESCE(SUM(attendance_status='alpha'),0) AS total_alpha,
                        COALESCE(SUM(attendance_status='sick'),0) AS total_sick,
                        COALESCE(SUM(attendance_status='permit'),0) AS total_permit,
                        COALESCE(SUM(attendance_status='annual'),0) AS total_annual,

                        COALESCE(SUM(late_minutes),0) AS total_late_minutes,
                        COALESCE(SUM(early_leave_minutes),0) AS total_early_leave_minutes,

                        COALESCE(SUM(work_hours),0) AS total_work_hours,
                        COALESCE(SUM(overtime_hours),0) AS total_overtime_hours

                    FROM k_attendances
                    WHERE employee_id = ?
                    AND attendance_date BETWEEN ? AND ?
                ", array(
                    $employee->id,
                    $startDate,
                    $endDate
                ))->row();

                $total_present = (int) $attendance->total_present;
                $total_late    = (int) $attendance->total_late;
                $total_alpha   = (int) $attendance->total_alpha;
                $total_sick    = (int) $attendance->total_sick;
                $total_permit  = (int) $attendance->total_permit;
                $total_annual  = (int) $attendance->total_annual;

                // Kehadiran
                $total_hadir = $total_present + $total_late;

                $attendance_percentage = 0;

                if ($total_hari_kerja > 0) {
                    $attendance_percentage = round(
                        ($total_hadir / $total_hari_kerja) * 100,
                        2
                    );
                }

                // SCOR
                $score = 100;

                // Alpha
                $score -= ($total_alpha * 20);

                // Telat
                $score -= ($total_late * 2);

                // Izin
                $score -= ($total_permit * 1);

                // Total menit telat
                $score -= floor(
                    ((int) $attendance->total_late_minutes) / 60
                );

                // Total menit pulang cepat
                $score -= floor(
                    ((int) $attendance->total_early_leave_minutes) / 120
                );

                if ($score < 0) {
                    $score = 0;
                }

                // LOGIKA STATUS
                if ($score >= 90) {
                    $status = 'baik sekali';
                } elseif ($score >= 75) {
                    $status = 'baik';
                } elseif ($score >= 60) {
                    $status = 'kurang baik';
                } else {
                    $status = 'buruk';
                }

                // INSERT OR UPDATE TO k_attendance_monthly
                $sql = "
                    INSERT INTO k_attendance_monthly (
                        employee_id, month,
                        total_present, total_late, total_alpha, total_sick, total_permit, total_annual,
                        total_late_minutes, total_early_leave_minutes,
                        total_work_hours, total_overtime_hours,
                        total_hari_kerja, total_hadir, attendance_percentage,
                        score, status
                    )
                    VALUES (
                        ?, ?,
                        ?, ?, ?, ?, ?, ?,
                        ?, ?,
                        ?, ?,
                        ?, ?, ?,
                        ?, ?
                    )
                    ON DUPLICATE KEY UPDATE
                        total_present = VALUES(total_present),
                        total_late = VALUES(total_late),
                        total_alpha = VALUES(total_alpha),
                        total_sick = VALUES(total_sick),
                        total_permit = VALUES(total_permit),
                        total_annual = VALUES(total_annual),
                        total_late_minutes = VALUES(total_late_minutes),
                        total_early_leave_minutes = VALUES(total_early_leave_minutes),
                        total_work_hours = VALUES(total_work_hours),
                        total_overtime_hours = VALUES(total_overtime_hours),
                        total_hari_kerja = VALUES(total_hari_kerja),
                        total_hadir = VALUES(total_hadir),
                        attendance_percentage = VALUES(attendance_percentage),
                        score = VALUES(score),
                        status = VALUES(status),
                        updated_at = CURRENT_TIMESTAMP
                ";

                $this->db->query($sql, array(
                    $employee->id,
                    $month,
                    $total_present,
                    $total_late,
                    $total_alpha,
                    $total_sick,
                    $total_permit,
                    $total_annual,
                    (int)$attendance->total_late_minutes,
                    (int)$attendance->total_early_leave_minutes,
                    (float)$attendance->total_work_hours,
                    (float)$attendance->total_overtime_hours,
                    $total_hari_kerja,
                    $total_hadir,
                    $attendance_percentage,
                    $score,
                    $status
                ));

                $processed++;
            }

            if ($this->db->trans_status() === FALSE) {
                throw new Exception('Transaction failed');
            }

            $this->db->trans_commit();

            echo json_encode(array(
                'status'    => true,
                'month'     => $month,
                'processed' => $processed,
                'message'   => 'Monthly attendance generated successfully'
            ));

        } catch (Exception $e) {

            $this->db->trans_rollback();

            echo json_encode(array(
                'status'  => false,
                'month'   => $month,
                'message' => $e->getMessage()
            ));
        }
    }

    // =====================================================
    // CRONJOB AUTO PENYUSUTAN ASSET BULANAN
    // =====================================================
    public function depreciation_asset()
    {
        $period = date('Y-m');
        $runDate = date('Y-m-d');
        $akun_beban_penyusutan = 54;

        $assets = $this->db
            ->select('id, nama_asset, nilai_perolehan, nilai_buku, nilai_residu, penyusutan_per_bulan, masa_manfaat, tanggal_perolehan, akumulasi_penyusutan, account_debit_id')
            ->from('assets')
            ->where('status', 'aktif')
            ->where('nilai_buku > nilai_residu', null, false)
            ->where('penyusutan_per_bulan >', 0)
            ->get()
            ->result();

        $processed = 0;
        $success = 0;
        $skipped = 0;
        $errors = 0;
        $details = [];

        $this->db->trans_begin();

        try {
            foreach ($assets as $a) {
                $processed++;

                $assetDetails = [
                    'asset_id' => (int)$a->id,
                    'asset_name' => $a->nama_asset,
                    'processed_months' => [],
                    'skipped_months' => []
                ];

                $account_parent = $this->db
                    ->select('id')
                    ->where('parent_id', $a->account_debit_id)
                    ->get('accounts')
                    ->row();

                if (!$account_parent || empty($account_parent->id)) {
                    $skipped++;
                    $assetDetails['status'] = 'skip';
                    $assetDetails['reason'] = 'account_parent_not_found';
                    $details[] = $assetDetails;
                    continue;
                }

                $akun_akumulasi_penyusutan = (int)$account_parent->id;

                $mutasiPatokan = $this->db
                    ->select('tanggal_dibuat')
                    ->from('asset_mutations')
                    ->where('asset_id', $a->id)
                    ->where_in('tipe', ['perolehan', 'penambahan'])
                    ->order_by('tanggal_dibuat', 'DESC')
                    ->order_by('id', 'DESC')
                    ->limit(1)
                    ->get()
                    ->row();

                $tanggalPatokan = null;
                if ($mutasiPatokan && !empty($mutasiPatokan->tanggal_dibuat)) {
                    $tanggalPatokan = $mutasiPatokan->tanggal_dibuat;
                }

                if (empty($tanggalPatokan)) {
                    $tanggalPatokan = $a->tanggal_perolehan;
                }

                if (empty($tanggalPatokan)) {
                    $skipped++;
                    $assetDetails['status'] = 'skip';
                    $assetDetails['reason'] = 'tanggal_patokan_tidak_ditemukan';
                    $details[] = $assetDetails;
                    continue;
                }

                $startMonth = date('Y-m', strtotime(date('Y-m-01', strtotime($tanggalPatokan)) . ' +1 month'));
                $currentMonth = $period;

                if ($startMonth > $currentMonth) {
                    $skipped++;
                    $assetDetails['status'] = 'skip';
                    $assetDetails['reason'] = 'start_next_month_after_acquisition';
                    $assetDetails['tanggal_patokan'] = $tanggalPatokan;
                    $details[] = $assetDetails;
                    continue;
                }

                $nilaiPerolehan = (float)$a->nilai_perolehan;
                $nilaiResidu = (float)$a->nilai_residu;
                $susutPerBulan = (float)$a->penyusutan_per_bulan;
                $masaManfaat = (int)$a->masa_manfaat;

                $akumulasiMutasi = $this->db
                    ->select('COALESCE(SUM(nilai),0) total', false)
                    ->from('asset_mutations')
                    ->where('asset_id', $a->id)
                    ->where('tipe', 'penyusutan')
                    ->get()
                    ->row();

                $akumulasiBerjalan = (float)($akumulasiMutasi ? $akumulasiMutasi->total : 0);
                $nilaiBukuBerjalan = $nilaiPerolehan - $akumulasiBerjalan;

                if ($nilaiBukuBerjalan < $nilaiResidu) {
                    $nilaiBukuBerjalan = $nilaiResidu;
                    $akumulasiBerjalan = $nilaiPerolehan - $nilaiBukuBerjalan;
                }

                $iterMonth = $startMonth;
                $assetHasSuccess = false;

                while ($iterMonth <= $currentMonth) {
                    $monthsUsed = 0;
                    $start = new DateTime(date('Y-m-01', strtotime($tanggalPatokan)));
                    $end   = new DateTime(date('Y-m-01', strtotime($iterMonth . '-01')));
                    $diff  = $start->diff($end);
                    $monthsUsed = ($diff->y * 12) + $diff->m;

                    if ($monthsUsed < 0) {
                        $skipped++;
                        $assetDetails['skipped_months'][] = [
                            'period' => $iterMonth,
                            'reason' => 'tanggal_patokan_after_period'
                        ];
                        $iterMonth = date('Y-m', strtotime($iterMonth . '-01 +1 month'));
                        continue;
                    }

                    if ($masaManfaat > 0 && $monthsUsed >= $masaManfaat) {
                        $skipped++;
                        $assetDetails['skipped_months'][] = [
                            'period' => $iterMonth,
                            'reason' => 'masa_manfaat_finished'
                        ];
                        break;
                    }

                    $acqDay = (int)date('d', strtotime($tanggalPatokan));
                    $lastDayOfMonth = (int)date('t', strtotime($iterMonth . '-01'));
                    $dueDay = min($acqDay, $lastDayOfMonth);
                    $dueDateThisMonth = $iterMonth . '-' . str_pad($dueDay, 2, '0', STR_PAD_LEFT);

                    // Untuk bulan berjalan, tetap hormati due date.
                    // Untuk bulan yang sudah lewat, langsung boleh diproses (catch-up).
                    if ($iterMonth === $currentMonth && strtotime($runDate) < strtotime($dueDateThisMonth)) {
                        $skipped++;
                        $assetDetails['skipped_months'][] = [
                            'period' => $iterMonth,
                            'reason' => 'not_due_date_today',
                            'due_date' => $dueDateThisMonth,
                            'run_date' => $runDate
                        ];
                        $iterMonth = date('Y-m', strtotime($iterMonth . '-01 +1 month'));
                        continue;
                    }

                    $startDate = $iterMonth . '-01';
                    $endDate   = date('Y-m-d', strtotime($startDate . ' +1 month'));

                    $already = $this->db
                        ->where('asset_id', $a->id)
                        ->where('tipe', 'penyusutan')
                        ->where('tanggal_dibuat >=', $startDate)
                        ->where('tanggal_dibuat <', $endDate)
                        ->count_all_results('asset_mutations');

                    if ($already > 0) {
                        $skipped++;
                        $assetDetails['skipped_months'][] = [
                            'period' => $iterMonth,
                            'reason' => 'already_depreciated_this_month'
                        ];
                        $iterMonth = date('Y-m', strtotime($iterMonth . '-01 +1 month'));
                        continue;
                    }

                    if ($nilaiBukuBerjalan <= $nilaiResidu) {
                        $skipped++;
                        $assetDetails['skipped_months'][] = [
                            'period' => $iterMonth,
                            'reason' => 'nothing_to_depreciate'
                        ];
                        break;
                    }

                    $maxSusut = max(0, $nilaiBukuBerjalan - $nilaiResidu);
                    $susut = min($susutPerBulan, $maxSusut);

                    if ($susut <= 0) {
                        $skipped++;
                        $assetDetails['skipped_months'][] = [
                            'period' => $iterMonth,
                            'reason' => 'nothing_to_depreciate'
                        ];
                        break;
                    }

                    $akumulasiBefore = $akumulasiBerjalan;
                    $nilaiBukuBefore = $nilaiBukuBerjalan;

                    $akumulasiBerjalan += $susut;
                    $nilaiBukuBerjalan = $nilaiPerolehan - $akumulasiBerjalan;

                    if ($nilaiBukuBerjalan < $nilaiResidu) {
                        $nilaiBukuBerjalan = $nilaiResidu;
                        $akumulasiBerjalan = $nilaiPerolehan - $nilaiBukuBerjalan;
                    }

                    $this->db->insert('asset_mutations', [
                        'asset_id' => $a->id,
                        'tipe' => 'penyusutan',
                        'nilai' => $susut,
                        'keterangan' => 'Penyusutan otomatis periode ' . $iterMonth . ' (cronjob)',
                        'tanggal_dibuat' => $dueDateThisMonth
                    ]);

                    $no_ref = 'DEP-' . date('YmdHis') . '-' . $a->id . '-' . str_replace('-', '', $iterMonth);
                    $this->db->insert('journals', [
                        'tanggal' => $dueDateThisMonth,
                        'no_ref' => $no_ref,
                        'keterangan' => 'Penyusutan Asset ' . $a->nama_asset . ' periode ' . $iterMonth,
                        'ref_type' => 'assets',
                        'ref_id' => $a->id,
                        'created_by' => 1
                    ]);

                    $jid = $this->db->insert_id();

                    $this->db->insert('journal_details', [
                        'journal_id' => $jid,
                        'account_id' => $akun_beban_penyusutan,
                        'debit' => $susut,
                        'kredit' => 0
                    ]);

                    $this->db->insert('journal_details', [
                        'journal_id' => $jid,
                        'account_id' => $akun_akumulasi_penyusutan,
                        'debit' => 0,
                        'kredit' => $susut
                    ]);

                    $success++;
                    $assetHasSuccess = true;

                    $assetDetails['processed_months'][] = [
                        'period' => $iterMonth,
                        'depreciation' => (float)$susut,
                        'due_date' => $dueDateThisMonth,
                        'akumulasi_before' => (float)$akumulasiBefore,
                        'akumulasi_after' => (float)$akumulasiBerjalan,
                        'nilai_buku_before' => (float)$nilaiBukuBefore,
                        'nilai_buku_after' => (float)$nilaiBukuBerjalan,
                        'journal_no_ref' => $no_ref
                    ];

                    $iterMonth = date('Y-m', strtotime($iterMonth . '-01 +1 month'));
                }

                if ($assetHasSuccess) {
                    $this->db->where('id', $a->id)->update('assets', [
                        'akumulasi_penyusutan' => $akumulasiBerjalan,
                        'nilai_buku' => $nilaiBukuBerjalan
                    ]);

                    $assetDetails['status'] = 'success';
                    $assetDetails['akumulasi_final'] = (float)$akumulasiBerjalan;
                    $assetDetails['nilai_buku_final'] = (float)$nilaiBukuBerjalan;
                } else {
                    $assetDetails['status'] = 'skip';
                    if (empty($assetDetails['reason'])) {
                        $assetDetails['reason'] = 'no_eligible_month_to_process';
                    }
                }

                $details[] = $assetDetails;
            }

            if ($this->db->trans_status() === FALSE) {
                throw new Exception('Transaction failed');
            }

            $this->db->trans_commit();

            echo json_encode([
                'status' => true,
                'period' => $period,
                'processed' => $processed,
                'success' => $success,
                'skipped' => $skipped,
                'errors' => $errors,
                'message' => 'Depreciation cron executed',
                'details' => $details
            ]);
        } catch (Exception $e) {
            $this->db->trans_rollback();
            $errors++;

            echo json_encode([
                'status' => false,
                'period' => $period,
                'processed' => $processed,
                'success' => $success,
                'skipped' => $skipped,
                'errors' => $errors,
                'message' => $e->getMessage()
            ]);
        }
    }

}
