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

class Payroll extends Auth_Controller
{
    public function __construct()
    {
        parent::__construct();
        $this->load->model(['Payroll_model']);
    }

    public function index()
    {
        $form_defaults = $this->session->flashdata('payroll_form_defaults');
        if (!is_array($form_defaults)) {
            $form_defaults = [
                'bulan' => (int) date('n'),
                'tahun' => (int) date('Y'),
                'tipe_periode' => 'REGULER',
                'catatan' => '',
            ];
        }

        $data = [
            'page_title'    => 'Sistem Payroll',
            'page_subtitle' => 'Kelola periode, proses hitung ulang, approval, lock, dan penghapusan payroll',
            'list'          => $this->Payroll_model->get_periode_list(),
            'mode'          => 'all',
            'open_create_modal' => (bool) $this->session->flashdata('open_payroll_modal'),
            'form_defaults' => $form_defaults,
        ];
        $this->render('transaksi/payroll/list', $data);
    }

    public function approval()
    {
        redirect('transaksi/payroll');
    }

    public function tambah()
    {
        $this->session->set_flashdata('open_payroll_modal', TRUE);
        redirect('transaksi/payroll');
    }

    public function simpan()
    {
        if ($this->input->server('REQUEST_METHOD') !== 'POST') {
            redirect('transaksi/payroll');
        }

        $bulan = (int) $this->input->post('bulan');
        $tahun = (int) $this->input->post('tahun');
        $tipe_periode = $this->input->post('tipe_periode', TRUE) ?: 'REGULER';
        if (!in_array($tipe_periode, ['REGULER', 'THR'], true)) {
            $tipe_periode = 'REGULER';
        }
        if ($bulan < 1 || $bulan > 12 || $tahun < 2000) {
            $this->session->set_flashdata('error', 'Periode tidak valid');
            $this->_redirect_to_index_with_form($bulan, $tahun, $tipe_periode);
        }

        if ($this->Payroll_model->periode_exists($bulan, $tahun, $tipe_periode)) {
            $this->session->set_flashdata('error', 'Periode payroll sudah ada');
            $this->_redirect_to_index_with_form($bulan, $tahun, $tipe_periode);
        }

        $resolved = resolve_payroll_period($bulan, $tahun, $tipe_periode);
        if (!$resolved) {
            $this->session->set_flashdata('error', 'Gagal menentukan rentang periode payroll. Periksa konfigurasi sistem.');
            $this->_redirect_to_index_with_form($bulan, $tahun, $tipe_periode);
        }

        $tanggal_mulai = $resolved['tanggal_mulai'];
        $tanggal_selesai = $resolved['tanggal_selesai'];

        if ($this->Payroll_model->periode_overlap_exists($tanggal_mulai, $tanggal_selesai, $tipe_periode)) {
            $this->session->set_flashdata('error', 'Rentang periode payroll overlap dengan periode lain bertipe sama. Periksa konfigurasi periode payroll terlebih dahulu.');
            $this->_redirect_to_index_with_form($bulan, $tahun, $tipe_periode);
        }

        $kode_suffix = $tipe_periode === 'THR' ? sprintf('%04d%02d_T', $tahun, $bulan) : sprintf('%04d%02d', $tahun, $bulan);

        $id = $this->Payroll_model->insert_periode([
            'kode_periode'    => $kode_suffix,
            'tipe_periode'    => $tipe_periode,
            'bulan'           => $bulan,
            'tahun'           => $tahun,
            'tanggal_mulai'   => $tanggal_mulai,
            'tanggal_selesai' => $tanggal_selesai,
            'status'          => 'DRAFT',
            'catatan'         => (string) $this->input->post('catatan'),
        ]);
        audit_log('INSERT', 'PayrollPeriode', 'ID: ' . $id . ' | Periode: ' . $bulan . '/' . $tahun . ' [' . $tipe_periode . ']');
        $this->session->set_flashdata('success', 'Periode payroll berhasil dibuat');
        redirect('transaksi/payroll');
    }

    private function _redirect_to_index_with_form($bulan, $tahun, $tipe_periode)
    {
        $this->session->set_flashdata('open_payroll_modal', TRUE);
        $this->session->set_flashdata('payroll_form_defaults', [
            'bulan' => (int) $bulan,
            'tahun' => (int) $tahun,
            'tipe_periode' => in_array($tipe_periode, ['REGULER', 'THR'], true) ? $tipe_periode : 'REGULER',
            'catatan' => (string) $this->input->post('catatan'),
        ]);
        redirect('transaksi/payroll');
    }

    public function detail($id_periode)
    {
        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode) {
            $this->session->set_flashdata('error', 'Periode tidak ditemukan');
            redirect('transaksi/payroll');
        }

        $data = [
            'page_title'    => 'Detail Payroll',
            'page_subtitle' => 'Periode ' . str_pad($periode->bulan, 2, '0', STR_PAD_LEFT) . '/' . $periode->tahun . ' (' . tgl_indonesia($periode->tanggal_mulai) . ' s/d ' . tgl_indonesia($periode->tanggal_selesai) . ')',
            'periode'       => $periode,
            'id_periode'    => (int) $id_periode,
        ];
        $this->render('transaksi/payroll/detail', $data);
    }

    public function ajax_detail_list($id_periode)
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
            return;
        }

        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode) {
            $this->output
                ->set_status_header(404)
                ->set_content_type('application/json')
                ->set_output(json_encode([
                    'draw' => 0,
                    'recordsTotal' => 0,
                    'recordsFiltered' => 0,
                    'data' => [],
                    'message' => 'Periode tidak ditemukan',
                ]));
            return;
        }

        $draw = (int) $this->input->post('draw');
        $start = (int) $this->input->post('start');
        $length = (int) $this->input->post('length');
        $search = trim((string) $this->input->post('search[value]', TRUE));
        $order_col = (int) $this->input->post('order[0][column]');
        $order_dir = (string) $this->input->post('order[0][dir]', TRUE);

        $total = $this->Payroll_model->datatable_detail_total((int) $id_periode);
        $filtered = $this->Payroll_model->datatable_detail_filtered((int) $id_periode, $search);
        $rows = $this->Payroll_model->datatable_detail_data((int) $id_periode, $start, $length, $search, $order_col, $order_dir);

        $data = [];
        foreach ($rows as $r) {
            $data[] = [
                'id_payroll' => (int) $r->id_payroll,
                'nip' => html_escape($r->nip),
                'nama_lengkap' => html_escape($r->nama_lengkap),
                'nama_divisi' => html_escape($r->nama_divisi),
                'gaji_pokok' => (float) $r->gaji_pokok,
                'gaji_pokok_text' => 'Rp ' . rupiah($r->gaji_pokok),
                'total_tunjangan' => (float) $r->total_tunjangan,
                'total_tunjangan_text' => 'Rp ' . rupiah($r->total_tunjangan),
                'total_lembur' => (float) $r->total_lembur,
                'total_lembur_text' => 'Rp ' . rupiah($r->total_lembur),
                'total_potongan' => (float) $r->total_potongan,
                'total_potongan_text' => 'Rp ' . rupiah($r->total_potongan),
                'gaji_neto' => (float) $r->gaji_neto,
                'gaji_neto_text' => 'Rp ' . rupiah($r->gaji_neto),
                'aksi' => '<button type="button" class="btn btn-xs btn-primary btn-detail-komponen" data-id="' . (int) $r->id_payroll . '" data-nama="' . html_escape($r->nama_lengkap) . '" title="Lihat Rincian Komponen"><i class="fa fa-eye"></i></button>',
            ];
        }

        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode([
                'draw' => $draw,
                'recordsTotal' => (int) $total,
                'recordsFiltered' => (int) $filtered,
                'data' => $data,
            ]));
    }

    public function detail_komponen_json($id_periode, $id_payroll)
    {
        if (!$this->input->is_ajax_request()) {
            show_404();
            return;
        }

        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode) {
            $this->output
                ->set_status_header(404)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => 'Periode tidak ditemukan']));
            return;
        }

        $payroll = $this->Payroll_model->get_payroll_single((int) $id_payroll);
        if (!$payroll || (int) $payroll->id_periode !== (int) $id_periode) {
            $this->output
                ->set_status_header(404)
                ->set_content_type('application/json')
                ->set_output(json_encode(['success' => false, 'message' => 'Data payroll tidak ditemukan']));
            return;
        }

        $adjustment_ready = $this->Payroll_model->is_adjustment_feature_ready();
        $komponen_rows = $this->Payroll_model->get_komponen_modal_by_payroll((int) $id_periode, (int) $id_payroll);

        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode([
                'success' => true,
                'can_adjust' => ((string) $periode->status === 'PROCESSED' && $adjustment_ready),
                'adjustment_ready' => $adjustment_ready,
                'adjustment_message' => $adjustment_ready
                    ? ''
                    : 'Fitur penyesuaian belum aktif karena tabel adjustment belum tersedia. Jalankan migration database terbaru.',
                'periode' => [
                    'id_periode' => (int) $periode->id_periode,
                    'bulan' => str_pad((string) $periode->bulan, 2, '0', STR_PAD_LEFT),
                    'tahun' => (int) $periode->tahun,
                    'status' => (string) $periode->status,
                ],
                'payroll' => [
                    'id_payroll' => (int) $payroll->id_payroll,
                    'nip' => (string) $payroll->nip,
                    'nama_lengkap' => (string) $payroll->nama_lengkap,
                    'divisi' => (string) ($payroll->nama_divisi ?? ''),
                    'jabatan' => (string) ($payroll->nama_jabatan ?? ''),
                ],
                'summary' => [
                    'gaji_pokok' => (float) $payroll->gaji_pokok,
                    'total_tunjangan' => (float) $payroll->total_tunjangan,
                    'total_lembur' => (float) $payroll->total_lembur,
                    'total_potongan' => (float) $payroll->total_potongan,
                    'gaji_neto' => (float) $payroll->gaji_neto,
                    'gaji_pokok_text' => 'Rp ' . rupiah($payroll->gaji_pokok),
                    'total_tunjangan_text' => 'Rp ' . rupiah($payroll->total_tunjangan),
                    'total_lembur_text' => 'Rp ' . rupiah($payroll->total_lembur),
                    'total_potongan_text' => 'Rp ' . rupiah($payroll->total_potongan),
                    'gaji_neto_text' => 'Rp ' . rupiah($payroll->gaji_neto),
                ],
                'komponen' => $this->_format_komponen_rows($komponen_rows),
            ]));
    }

    public function adjustment_save()
    {
        if ($this->input->server('REQUEST_METHOD') !== 'POST' || !$this->input->is_ajax_request()) {
            show_404();
            return;
        }

        if (!$this->Payroll_model->is_adjustment_feature_ready()) {
            return $this->_json_adjustment_error('Fitur penyesuaian belum aktif. Jalankan migration payroll adjustment terlebih dahulu.');
        }

        $id_periode = (int) $this->input->post('id_periode');
        $id_payroll = (int) $this->input->post('id_payroll');
        $id_adjustment = (int) $this->input->post('id_adjustment');

        $periode = $this->Payroll_model->get_periode_by_id($id_periode);
        if (!$periode) {
            return $this->_json_adjustment_error('Periode tidak ditemukan');
        }
        if ((string) $periode->status !== 'PROCESSED') {
            return $this->_json_adjustment_error('Penyesuaian hanya diizinkan saat status periode PROCESSED');
        }

        $payroll = $this->Payroll_model->get_payroll_single($id_payroll);
        if (!$payroll || (int) $payroll->id_periode !== $id_periode) {
            return $this->_json_adjustment_error('Data payroll tidak ditemukan');
        }

        $payload = [
            'id_adjustment' => $id_adjustment,
            'id_periode' => $id_periode,
            'id_payroll' => $id_payroll,
            'id_pegawai' => (int) $payroll->id_pegawai,
            'nama_komponen' => (string) $this->input->post('nama_komponen', TRUE),
            'jenis' => (string) $this->input->post('jenis', TRUE),
            'nilai' => (float) $this->input->post('nilai', TRUE),
            'catatan' => (string) $this->input->post('catatan', TRUE),
        ];

        $result = $this->Payroll_model->save_custom_adjustment($payload, (int) $this->session->userdata('id_user'));
        if (!$result['success']) {
            return $this->_json_adjustment_error($result['message'] ?? 'Gagal menyimpan penyesuaian');
        }

        $action = $id_adjustment > 0 ? 'UPDATE' : 'INSERT';
        audit_log($action, 'PayrollAdjustment', 'Periode ID: ' . $id_periode . ' | Payroll ID: ' . $id_payroll . ' | Pegawai ID: ' . (int) $payroll->id_pegawai . ' | Nama: ' . (string) $payload['nama_komponen'] . ' | Jenis: ' . strtoupper((string) $payload['jenis']) . ' | Nilai: ' . (float) $payload['nilai']);

        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode([
                'success' => true,
                'message' => $result['message'],
                'summary' => $this->_format_summary_payload($result['summary'] ?? []),
                'komponen' => $this->_format_komponen_rows($result['komponen'] ?? []),
            ]));
    }

    public function adjustment_delete()
    {
        if ($this->input->server('REQUEST_METHOD') !== 'POST' || !$this->input->is_ajax_request()) {
            show_404();
            return;
        }

        if (!$this->Payroll_model->is_adjustment_feature_ready()) {
            return $this->_json_adjustment_error('Fitur penyesuaian belum aktif. Jalankan migration payroll adjustment terlebih dahulu.');
        }

        $id_periode = (int) $this->input->post('id_periode');
        $id_payroll = (int) $this->input->post('id_payroll');
        $id_adjustment = (int) $this->input->post('id_adjustment');

        if ($id_adjustment < 1) {
            return $this->_json_adjustment_error('ID penyesuaian tidak valid');
        }

        $periode = $this->Payroll_model->get_periode_by_id($id_periode);
        if (!$periode) {
            return $this->_json_adjustment_error('Periode tidak ditemukan');
        }
        if ((string) $periode->status !== 'PROCESSED') {
            return $this->_json_adjustment_error('Penyesuaian hanya diizinkan saat status periode PROCESSED');
        }

        $payroll = $this->Payroll_model->get_payroll_single($id_payroll);
        if (!$payroll || (int) $payroll->id_periode !== $id_periode) {
            return $this->_json_adjustment_error('Data payroll tidak ditemukan');
        }

        $result = $this->Payroll_model->delete_custom_adjustment(
            $id_adjustment,
            $id_periode,
            $id_payroll,
            (int) $payroll->id_pegawai,
            (int) $this->session->userdata('id_user')
        );
        if (!$result['success']) {
            return $this->_json_adjustment_error($result['message'] ?? 'Gagal menghapus penyesuaian');
        }

        audit_log('DELETE', 'PayrollAdjustment', 'Periode ID: ' . $id_periode . ' | Payroll ID: ' . $id_payroll . ' | Pegawai ID: ' . (int) $payroll->id_pegawai . ' | Adjustment ID: ' . $id_adjustment);

        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode([
                'success' => true,
                'message' => $result['message'],
                'summary' => $this->_format_summary_payload($result['summary'] ?? []),
                'komponen' => $this->_format_komponen_rows($result['komponen'] ?? []),
            ]));
    }

    private function _format_summary_payload(array $summary)
    {
        return [
            'gaji_pokok' => (float) ($summary['gaji_pokok'] ?? 0),
            'total_tunjangan' => (float) ($summary['total_tunjangan'] ?? 0),
            'total_lembur' => (float) ($summary['total_lembur'] ?? 0),
            'total_potongan' => (float) ($summary['total_potongan'] ?? 0),
            'gaji_neto' => (float) ($summary['gaji_neto'] ?? 0),
            'gaji_pokok_text' => 'Rp ' . rupiah($summary['gaji_pokok'] ?? 0),
            'total_tunjangan_text' => 'Rp ' . rupiah($summary['total_tunjangan'] ?? 0),
            'total_lembur_text' => 'Rp ' . rupiah($summary['total_lembur'] ?? 0),
            'total_potongan_text' => 'Rp ' . rupiah($summary['total_potongan'] ?? 0),
            'gaji_neto_text' => 'Rp ' . rupiah($summary['gaji_neto'] ?? 0),
        ];
    }

    private function _format_komponen_rows(array $rows)
    {
        $result = [];
        foreach ($rows as $item) {
            if (is_array($item)) {
                $row = $item;
            } else {
                $row = [
                    'id_adjustment' => null,
                    'jenis' => (string) $item->jenis,
                    'nama_komponen' => (string) $item->nama_komponen,
                    'tipe_nilai' => (string) $item->tipe_nilai,
                    'jumlah_hari' => $item->jumlah_hari !== null ? (int) $item->jumlah_hari : null,
                    'sumber' => (string) $item->sumber,
                    'nilai' => (float) $item->nilai,
                    'catatan' => null,
                    'is_custom' => false,
                    'is_editable' => false,
                ];
            }

            $result[] = [
                'id_adjustment' => isset($row['id_adjustment']) && $row['id_adjustment'] !== null ? (int) $row['id_adjustment'] : null,
                'jenis' => (string) ($row['jenis'] ?? ''),
                'nama_komponen' => (string) ($row['nama_komponen'] ?? ''),
                'tipe_nilai' => (string) ($row['tipe_nilai'] ?? 'NOMINAL'),
                'jumlah_hari' => isset($row['jumlah_hari']) && $row['jumlah_hari'] !== null ? (int) $row['jumlah_hari'] : null,
                'sumber' => (string) ($row['sumber'] ?? ''),
                'nilai' => (float) ($row['nilai'] ?? 0),
                'nilai_text' => 'Rp ' . rupiah((float) ($row['nilai'] ?? 0)),
                'catatan' => (string) ($row['catatan'] ?? ''),
                'is_custom' => !empty($row['is_custom']),
                'is_editable' => !empty($row['is_editable']),
            ];
        }
        return $result;
    }

    private function _json_adjustment_error($message)
    {
        $this->output
            ->set_content_type('application/json')
            ->set_output(json_encode([
                'success' => false,
                'message' => (string) $message,
            ]));
        return;
    }

    public function proses($id_periode)
    {
        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode) {
            $this->session->set_flashdata('error', 'Periode tidak ditemukan');
            redirect('transaksi/payroll');
        }

        if ($periode->status === 'LOCKED') {
            $this->session->set_flashdata('error', 'Periode LOCKED tidak dapat diproses ulang');
            redirect('transaksi/payroll');
        }

        $result = $this->Payroll_model->process_payroll((int) $id_periode, (int) $this->session->userdata('id_user'));
        if (!$result['success']) {
            $this->session->set_flashdata('error', $result['message']);
            redirect('transaksi/payroll');
        }

        audit_log('PROCESS', 'Payroll', 'Periode ID: ' . $id_periode . ' | Pegawai diproses: ' . $result['processed']);
        $this->session->set_flashdata('success', $result['message'] . ' (' . $result['processed'] . ' pegawai)');
        redirect('transaksi/payroll/detail/' . (int) $id_periode);
    }

    /**
     * AJAX API: proses payroll dengan opsi (mode dan pegawai terpilih).
     * Mengembalikan JSON: { success: bool, message: string, processed: int }
     */
    public function proses_api($id_periode)
    {
        if ($this->input->server('REQUEST_METHOD') !== 'POST') {
            show_404();
            return;
        }

        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode) {
            echo json_encode(['success' => false, 'message' => 'Periode tidak ditemukan']);
            return;
        }

        if ($periode->status === 'LOCKED') {
            echo json_encode(['success' => false, 'message' => 'Periode LOCKED tidak dapat diproses ulang']);
            return;
        }

        $mode = strtolower((string) $this->input->post('mode', TRUE));
        $mode = $mode === 'tanpa_absensi' ? 'tanpa_absensi' : 'absensi';
        $employees = $this->input->post('employees');
        if (!is_array($employees)) {
            $employees = [];
        }

        $select_all = (int) $this->input->post('select_all');
        $search_value = (string) $this->input->post('search_value');

        if ($select_all === 1) {
            // Build list of employee ids matching current search (or all active if empty)
            $this->db->select('id_pegawai')->from('tb_pegawai')->where('status_pegawai', 'AKTIF');
            if ($search_value !== '') {
                $this->db->join('tb_divisi', 'tb_divisi.id_divisi = tb_pegawai.id_divisi', 'left');
                $this->db->group_start();
                $this->db->like('tb_pegawai.nip', $search_value);
                $this->db->or_like('tb_pegawai.nama_lengkap', $search_value);
                $this->db->or_like('tb_divisi.nama_divisi', $search_value);
                $this->db->group_end();
            }
            $rows = $this->db->get()->result();
            $employees = array_map(function($r){ return (int)$r->id_pegawai; }, $rows);
        }

        $result = $this->Payroll_model->process_payroll_with_options((int) $id_periode, (int) $this->session->userdata('id_user'), $mode, $employees);

        if ($result['success']) {
            audit_log('PROCESS', 'Payroll', 'Periode ID: ' . $id_periode . ' | Mode: ' . $mode . ' | Pegawai diproses: ' . $result['processed']);
        }

        echo json_encode($result);
    }

    /**
     * AJAX: daftar pegawai aktif untuk selector pada modal proses.
     * Mengembalikan JSON array pegawai { id_pegawai, nip, nama_lengkap, nama_divisi }
     */
    public function ajax_employees($id_periode)
    {
        // Server-side processing for DataTables
        $this->output->set_content_type('application/json');

        $draw = (int) $this->input->post('draw');
        $start = (int) $this->input->post('start');
        $length = (int) $this->input->post('length');
        $search = $this->input->post('search');
        $search_value = isset($search['value']) ? trim($search['value']) : '';

        // Total records (without search)
        $recordsTotal = $this->db->from('tb_pegawai')->where('status_pegawai', 'AKTIF')->count_all_results();

        // Build filtered query (include divisi join for search)
        $this->db->from('tb_pegawai')->where('status_pegawai', 'AKTIF');
        $this->db->join('tb_divisi', 'tb_divisi.id_divisi = tb_pegawai.id_divisi', 'left');
        if ($search_value !== '') {
            $this->db->group_start();
            $this->db->like('tb_pegawai.nip', $search_value);
            $this->db->or_like('tb_pegawai.nama_lengkap', $search_value);
            $this->db->or_like('tb_divisi.nama_divisi', $search_value);
            $this->db->group_end();
        }

        // Ordering (safe access)
        $order_col = null;
        $order_dir = 'asc';
        $order = $this->input->post('order');
        if (!empty($order) && isset($order[0]['column'])) {
            $order_col = $order[0]['column'];
            $order_dir = isset($order[0]['dir']) ? $order[0]['dir'] : 'asc';
        }
        if ($order_col !== null) {
            $map = [1 => 'nip', 2 => 'nama_lengkap', 3 => 'tb_divisi.nama_divisi'];
            $col = $map[(int)$order_col] ?? 'nama_lengkap';
            $this->db->order_by($col, strtolower($order_dir) === 'desc' ? 'DESC' : 'ASC');
        } else {
            $this->db->order_by('nama_lengkap', 'ASC');
        }

        // recordsFiltered
        $recordsFiltered = $this->db->count_all_results('', false);

        // Paging
        if ($length > 0) {
            $this->db->limit($length, $start);
        }

        // select columns from current query (divisi already joined above)
        $this->db->select('tb_pegawai.id_pegawai, tb_pegawai.nip, tb_pegawai.nama_lengkap, tb_divisi.nama_divisi');
        $rows = $this->db->get()->result();

        $data = [];
        foreach ($rows as $r) {
            $data[] = [
                'id' => (int) $r->id_pegawai,
                'nip' => (string) $r->nip,
                'nama' => (string) $r->nama_lengkap,
                'divisi' => (string) ($r->nama_divisi ?? ''),
            ];
        }

        echo json_encode([
            'draw' => $draw,
            'recordsTotal' => (int) $recordsTotal,
            'recordsFiltered' => (int) $recordsFiltered,
            'data' => $data,
        ]);
    }

    public function approve($id_periode)
    {
        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode || $periode->status !== 'PROCESSED') {
            $this->session->set_flashdata('error', 'Hanya periode PROCESSED yang dapat di-approve');
            redirect('transaksi/payroll');
        }

        $this->Payroll_model->update_periode_status((int) $id_periode, 'APPROVED', (int) $this->session->userdata('id_user'));
        audit_log('APPROVE', 'Payroll', 'Periode ID: ' . $id_periode);
        $this->session->set_flashdata('success', 'Periode payroll di-approve');
        redirect('transaksi/payroll');
    }

    public function lock($id_periode)
    {
        $periode = $this->Payroll_model->get_periode_by_id((int) $id_periode);
        if (!$periode || !in_array($periode->status, ['APPROVED', 'LOCKED'])) {
            $this->session->set_flashdata('error', 'Periode harus APPROVED sebelum LOCK');
            redirect('transaksi/payroll');
        }

        if ($periode->status !== 'LOCKED') {
            $this->Payroll_model->update_periode_status((int) $id_periode, 'LOCKED', (int) $this->session->userdata('id_user'));
            audit_log('LOCK', 'Payroll', 'Periode ID: ' . $id_periode);
        }

        $this->session->set_flashdata('success', 'Periode payroll di-lock');
        redirect('transaksi/payroll');
    }

    public function hapus($id_periode)
    {
        $is_superadmin = ((string) $this->session->userdata('role') === 'SUPERADMIN');
        if (!$this->Payroll_model->delete_draft_periode((int) $id_periode, $is_superadmin)) {
            $this->session->set_flashdata('error', $is_superadmin
                ? 'Periode gagal dihapus.'
                : 'Hanya periode DRAFT yang dapat dihapus');
            redirect('transaksi/payroll');
        }

        audit_log('DELETE', 'PayrollPeriode', 'Periode ID: ' . (int) $id_periode);
        $this->session->set_flashdata('success', 'Periode payroll dihapus');
        redirect('transaksi/payroll');
    }
}
