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

class Invoices extends CI_Controller {

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

        $this->load->model('DynamicModel', 'dm');
        
        if (!$this->session->userdata('logged_in')) {
            redirect('auth');
        }
    }

    // =========================
    // VIEW
    // =========================

    public function paid()
    {
        $data = ["active_menu" => "invoice_paid"];
        $this->load->view('partials/header', $data);
        $this->load->view('invoices/layout');
        $this->load->view('partials/footer');
    }

    public function draft()
    {
        $data = ["active_menu" => "invoice_draft"];
        $this->load->view('partials/header', $data);
        $this->load->view('invoices/layout');
        $this->load->view('partials/footer');
    }

    // =========================
    // GET DATA (FILTER STATUS)
    // =========================

    public function get_data($status = null)
    {
        $this->db->select('
            invoices.id,
            invoices.customer_id,
            invoices.no_invoice,
            invoices.tanggal,
            invoices.jatuh_tempo,
            invoices.total,
            invoices.total_bayar,
            invoices.sisa_piutang,
            invoices.status,
            customers.nama
        ');
        $this->db->from('invoices');
        $this->db->join('customers','customers.id = invoices.customer_id');

        // =========================
        // FILTER STATUS
        // =========================
        if ($status) {
            if($status == 'draft'){
                $this->db->where_in('invoices.status', ['unpaid','partial','draft']);
            } else {
                $this->db->where('invoices.status', $status);
            }
        }

        $this->db->where('invoices.deleted_at IS NULL', null, false);
        $this->db->order_by('invoices.tanggal','DESC');
        $this->db->order_by('customers.nama','ASC');

        $data = $this->db->get()->result();

        $result = [];
        $no = 1;

        foreach ($data as $row) {

            // =========================
            // CEK TUNGGAKAN SEBELUMNYA
            // =========================
            $this->db->select_sum('sisa_piutang');
            $this->db->where('customer_id', $row->customer_id);
            $this->db->where('status !=', 'paid');
            $this->db->where('id <', $row->id);

            $tunggakan = $this->db->get('invoices')->row()->sisa_piutang ?? 0;

            // =========================
            // STATUS BADGE
            // =========================
            switch ($row->status) {

                case 'paid':
                    $status_badge = '<span class="badge bg-success px-3 py-1">PAID</span>';
                    break;

                case 'partial':
                    $status_badge = '<span class="badge bg-warning px-3 py-1">PARTIAL</span>';
                    break;

                case 'unpaid':
                    $status_badge = '<span class="badge bg-danger px-3 py-1">UNPAID</span>';
                    break;

                default:
                    $status_badge = '<span class="badge bg-secondary px-3 py-1">DRAFT</span>';
            }

            // =========================
            // AKSI
            // =========================
            $aksi = '';

            // tombol detail
            $aksi .= '<button class="btn btn-sm btn-secondary btn-detail mt-1 ml-1"
                        data-id="'.$row->id.'"
                        data-status="'.$row->status.'">
                        Detail
                      </button> ';

            // =========================
            // LOGIC BAYAR
            // =========================
            $bolehBayar = ($tunggakan <= 0);

            // DRAFT
            if($row->status == 'draft'){

                if ($row->total > 0 && $bolehBayar) {
                    $aksi .= '<button class="btn btn-sm btn-success btn-bayar mt-1 ml-1"
                            data-id="'.$row->id.'"
                            data-total="'.$row->total.'"
                            data-terbayar="'.$row->total_bayar.'"
                            data-sisa="'.$row->sisa_piutang.'"
                            data-customer="'.$row->nama.'"
                            data-invoice="'.$row->no_invoice.'">
                            Bayar
                          </button> ';
                }

                $aksi .= '<button class="btn btn-sm btn-danger btn-delete mt-1 ml-1" data-id="'.$row->id.'">
                            Delete
                          </button>';
            }

            // UNPAID + PARTIAL
            if(in_array($row->status, ['unpaid','partial'])){

                if($bolehBayar){
                    $aksi .= '<button class="btn btn-sm btn-success btn-bayar mt-1 ml-1"
                                data-id="'.$row->id.'"
                                data-total="'.$row->total.'"
                                data-terbayar="'.$row->total_bayar.'"
                                data-sisa="'.$row->sisa_piutang.'"
                                data-customer="'.$row->nama.'"
                                data-invoice="'.$row->no_invoice.'">
                                Bayar
                              </button> ';
                } else {
                    // indikator tunggakan
                    $aksi .= '<span class="badge bg-danger mt-1 ml-1">
                                Ada tunggakan
                              </span>';
                }
            }

            // =========================
            // FORMAT OUTPUT
            // =========================
            $result[] = [
                $no++,
                '<b>'.$row->no_invoice.'</b>',
                tanggal_indo($row->tanggal),
                tanggal_indo($row->jatuh_tempo),
                $row->nama,
                '<span class="text-dark fw-bold">Rp '.number_format($row->total,0,',','.').'</span>',
                '<span class="text-success">Rp '.number_format($row->total_bayar,0,',','.').'</span>',
                '<span class="text-danger fw-bold">Rp '.number_format($row->sisa_piutang,0,',','.').'</span>',
                $status_badge,
                $aksi
            ];
        }

        echo json_encode(["data"=>$result]);
    }

    // =========================
    // GET CUSTOMER
    // =========================
    public function get_customers()
    {
        echo json_encode($this->db->get('customers')->result());
    }

    // =========================
    // SAVE INVOICE
    // =========================
    public function save()
    {
        $this->output->set_content_type('application/json');
    
        $customer_id = $this->input->post('customer_id');
        $tanggal     = $this->input->post('tanggal');
        $jatuh_tempo = $this->input->post('jatuh_tempo');
    
        // =========================
        // VALIDASI WAJIB FIELD
        // =========================
        if (empty($customer_id) || empty($tanggal) || empty($jatuh_tempo)) {
            echo json_encode([
                'status' => false,
                'message' => 'Customer, tanggal, dan jatuh tempo wajib diisi'
            ]);
            return;
        }
    
        // =========================
        // NORMALISASI TANGGAL
        // =========================
        $today        = date('Y-m-d');
        $tanggal      = date('Y-m-d', strtotime($tanggal));
        $jatuh_tempo  = date('Y-m-d', strtotime($jatuh_tempo));
    
    
        // ❌ jatuh tempo tidak boleh kurang dari tanggal invoice
        if ($jatuh_tempo < $tanggal) {
            echo json_encode([
                'status' => false,
                'message' => 'Jatuh tempo tidak boleh lebih kecil dari tanggal invoice'
            ]);
            return;
        }
    
        // =========================
        // GENERATE NO INVOICE
        // =========================
        $tanggal_now = date('Ymd');
    
        $this->db->like('no_invoice', 'INV-'.$tanggal_now, 'after');
        $this->db->from('invoices');
        $count = $this->db->count_all_results();
    
        $urutan = str_pad($count + 1, 4, '0', STR_PAD_LEFT);
    
        $no_invoice = 'INV-' . $tanggal_now . '-' . $urutan;
        
        // =========================
        // HANDEL A<BIL CICILAN JIKA ADA
        // =========================
        $cicilan_raw = $this->db->query("
            SELECT *
            FROM invoice_installments
            WHERE customer_id = ?
            AND status IN ('unpaid','partial')
            AND (nominal - paid_amount) > 0
            AND is_billed = 0
            ORDER BY invoice_detail_id, angsuran_ke ASC
        ", [$customer_id])->result();
        
        $cicilan = [];
        $group = [];
        
        foreach ($cicilan_raw as $c) {
            $group[$c->invoice_detail_id][] = $c;
        }
        
        foreach ($group as $detail_id => $rows) {
        
            $picked_status = [];
            $min_row = null;
        
            foreach ($rows as $r) {
        
                // ambil angsuran terkecil
                if ($min_row === null) {
                    $min_row = $r;
                    $picked_status[$r->status] = true;
                    $cicilan[] = $r;
                    continue;
                }
        
                // ambil jika status beda dan belum pernah diambil
                if (!isset($picked_status[$r->status])) {
                    $picked_status[$r->status] = true;
                    $cicilan[] = $r;
                }
            }
        }

        // =========================
        // TRANSACTION
        // =========================
        $this->db->trans_start();
        
        $this->db->insert('invoices', [
            'no_invoice'  => $no_invoice,
            'customer_id' => $customer_id,
            'tanggal'     => $tanggal,
            'jatuh_tempo' => $jatuh_tempo,
            'total'       => 0,
            'status'      => 'draft'
        ]);
        
        $invoice_id = $this->db->insert_id();
        
        $total_invoice = 0;
        
        foreach ($cicilan as $c) {
        
            // ambil data item asli
            $inv_items = $this->db
                ->select('account_id, items_id, nama_item, keterangan, subtotal_asli, is_cicilan')
                ->where('id', $c->invoice_detail_id)
                ->get('invoice_details')
                ->row();
        
            if(!$inv_items) continue;
        
            // =========================
            // FORMAT NAMA
            // =========================
            if($c->paid_amount > 0){
                $priodecicilan = '( Sisa Cicilan ke ' . $c->angsuran_ke . '/' . $c->total_angsuran . ' )';
            }else{
                $priodecicilan = '( Cicilan ke ' . $c->angsuran_ke . '/' . $c->total_angsuran . ' )';
            }
        
            $nama_item = preg_replace(
                '/\s*\(\s*Cicilan.*$/i',
                '',
                $inv_items->nama_item
            ) . ' ' . $priodecicilan;
        
            // =========================
            // NOMINAL
            // =========================
            $harga_cicilan = max(0, $c->nominal - $c->paid_amount);
            if($harga_cicilan <= 0) continue;
        
            // =========================
            // INSERT DETAIL
            // =========================
            $insert_data = [
                'invoice_id'    => $invoice_id,
                'tanggal'       => $tanggal,
                'account_id'    => $inv_items->account_id,
                'items_id'      => $inv_items->items_id ?: null,
                'nama_item'     => $nama_item,
                'qty'           => 1,
                'harga'         => $harga_cicilan,
                'subtotal'      => $harga_cicilan,
                'warehouse_id'  => null,
                'keterangan'    => $inv_items->keterangan,
                'subtotal_asli' => $inv_items->subtotal_asli,
                'is_cicilan'    => $inv_items->is_cicilan
            ];
        
            $this->db->insert('invoice_details', $insert_data);
        
            // =========================
            // AKUMULASI TOTAL
            // =========================
            $total_invoice += $harga_cicilan;
        
            // =========================
            // MARK SUDAH DITAGIHKAN
            // =========================
            $this->db->where('id', $c->id)->update('invoice_installments', [
                'is_billed' => 1
            ]);
        }
        
        // =========================
        // UPDATE TOTAL INVOICE
        // =========================
        $this->update_total($invoice_id);
        
        $this->db->trans_complete();
    
        // =========================
        // RESPONSE
        // =========================
        if (!$this->db->trans_status()) {
            echo json_encode([
                'status' => false,
                'message' => 'Gagal membuat invoice'
            ]);
            return;
        }
    
        log_activity(
            'invoice',
            'create',
            'Membuat invoice ' . $no_invoice . ' untuk customer ID ' . $customer_id,
            'success'
        );
    
        echo json_encode([
            'status' => true,
            'invoice_id' => $invoice_id,
            'no_invoice' => $no_invoice
        ]);
    }
    
    public function bayar()
    {
        $this->output->set_content_type('application/json');
    
        $invoice_id     = $this->input->post('invoice_id');
        $tanggal_bayar  = $this->input->post('tanggal_bayar');
        $detail         = $this->input->post('detail');
    
        if(!$invoice_id || empty($detail)){
            echo json_encode(['status'=>false,'message'=>'Data tidak valid']);
            return;
        }
    
        $invoice = $this->db->get_where('invoices',['id'=>$invoice_id])->row();
        if(!$invoice){
            echo json_encode(['status'=>false,'message'=>'Invoice tidak ditemukan']);
            return;
        }
    
        $customer = $this->db->get_where('customers',['id'=>$invoice->customer_id])->row();
        if(!$customer){
            echo json_encode(['status'=>false,'message'=>'Customer tidak ditemukan']);
            return;
        }
    
        // =========================
        // HITUNG TOTAL BAYAR
        // =========================
        $total_bayar_input = 0;
        foreach ($detail as $d) {
            $total_bayar_input += (float)$d['amount'];
        }
    
        if($total_bayar_input <= 0){
            echo json_encode(['status'=>false,'message'=>'Total bayar harus > 0']);
            return;
        }
    
        // =========================
        // DATA INVOICE
        // =========================
        $paid_before   = (float)$invoice->total_bayar;
        $total_invoice = (float)$invoice->total;
    
        $new_total_bayar = $paid_before + $total_bayar_input;
        $sisa_setelah    = $total_invoice - $new_total_bayar;
    
        if($new_total_bayar > $total_invoice){
            echo json_encode([
                'status'=>false,
                'message'=>'Pembayaran melebihi total invoice'
            ]);
            return;
        }
    
        // =========================
        // AKUN
        // =========================
        $akun_tabungan = 70;
        $akun_barang   = 62;
        $akun_piutang  = 19;
    
        // =========================
        // HITUNG TOTAL CICILAN
        // =========================
    
        $cicilan = $this->db->query("
            SELECT ii.*
            FROM invoice_installments ii
            JOIN (
                SELECT invoice_detail_id, MIN(angsuran_ke) as angsuran_ke
                FROM invoice_installments
                WHERE customer_id = ?
                AND status != 'paid'
                GROUP BY invoice_detail_id
            ) x 
            ON x.invoice_detail_id = ii.invoice_detail_id 
            AND x.angsuran_ke = ii.angsuran_ke
        ", [$customer->id])->result();
        
        $total_cicilan = 0;
    
        foreach($cicilan as $c){
            $total_cicilan += ($c->nominal - $c->paid_amount);
        }
    
        // =========================
        // TOTAL PER KATEGORI
        // =========================
        $total_tabungan = (float) $this->db
            ->select('SUM(subtotal) as total')
            ->where('invoice_id', $invoice_id)
            ->where('account_id', $akun_tabungan)
            ->get('invoice_details')->row()->total ?? 0;
    
        $total_barang = (float) $this->db
            ->select('SUM(subtotal) as total')
            ->where('invoice_id', $invoice_id)
            ->where('account_id', $akun_barang)
            ->get('invoice_details')->row()->total ?? 0;
    
        $total_other = (float) $this->db
            ->select('SUM(subtotal) as total')
            ->where('invoice_id', $invoice_id)
            ->where_not_in('account_id', [$akun_tabungan, $akun_barang])
            ->get('invoice_details')->row()->total ?? 0;
    
        // =========================
        // SISA PER KATEGORI
        // =========================
        $sisa_other    = max(0, $total_other - $paid_before);
        $sisa_tabungan = max(0, $total_tabungan - max(0, $paid_before - $total_other));
        $sisa_barang   = max(0, $total_barang - max(0, $paid_before - $total_other - $total_tabungan));
    
        // =========================
        // ALOKASI
        // =========================
        $sisa_bayar = $total_bayar_input;
        
        // =========================
        // 1. CICILAN (PER ITEM)
        // =========================
        $bayar_cicilan = min($sisa_bayar, $total_cicilan);
        $sisa_bayar   -= $bayar_cicilan;
    
        // =========================
        // 2. OTHER
        // =========================
        $bayar_other = min($sisa_bayar, $sisa_other);
        $sisa_bayar -= $bayar_other;
    
        // =========================
        // 3. TABUNGAN
        // =========================
        $bayar_tabungan = min($sisa_bayar, $sisa_tabungan);
        $sisa_bayar -= $bayar_tabungan;
    
        // =========================
        // 4. BARANG
        // =========================
        $bayar_barang = min($sisa_bayar, $sisa_barang);
        $sisa_bayar -= $bayar_barang;
    
        // =========================
        // TRANSACTION
        // =========================
        $this->db->trans_start();
        
        // UPDATE invoice_installments jika perlu di update
        if($bayar_cicilan > 0){
        
            $sisa = $bayar_cicilan; // ✅ FIX
        
            foreach($cicilan as $c){
        
                if($sisa <= 0) break;
        
                $kurang = $c->nominal - $c->paid_amount;
                $bayar  = min($sisa, $kurang);
        
                $sisa -= $bayar;
        
                $new_paid = $c->paid_amount + $bayar;
                $status   = ($new_paid >= $c->nominal) ? 'paid' : 'partial';
        
                $this->db->where('id',$c->id)->update('invoice_installments',[
                    'paid_amount' => $new_paid,
                    'status'      => $status
                ]);
            }
        }
    
        $no_ref = 'PAY-' . date('YmdHis');
    
        $this->db->insert('journals', [
            'tanggal'   => $tanggal_bayar,
            'no_ref'    => $no_ref,
            'keterangan'=> 'Diterima Pembayaran Invoice '.$invoice->no_invoice.' ('.$customer->nama.')',
            'ref_type'  => 'invoice_payment',
            'ref_id'    => $invoice_id,
            'created_by'=> $this->session->userdata('user_id')
        ]);
    
        $journal_id = $this->db->insert_id();
    
        // DEBIT
        $total_debit = 0;
        foreach ($detail as $d) {
            if(empty($d['account_id']) || $d['amount'] <= 0) continue;
    
            $this->db->insert('journal_details', [
                'journal_id' => $journal_id,
                'account_id' => $d['account_id'],
                'debit'      => $d['amount'],
                'kredit'     => 0
            ]);
    
            $total_debit += $d['amount'];
        }
    
        // =========================
        // KREDIT
        // =========================
        $total_kredit = 0;
    
        $kredit_piutang = $bayar_cicilan + $bayar_other + $bayar_barang;
    
        if($kredit_piutang > 0){
            $this->db->insert('journal_details', [
                'journal_id'=>$journal_id,
                'account_id'=>$akun_piutang,
                'debit'=>0,
                'kredit'=>$kredit_piutang
            ]);
            $total_kredit += $kredit_piutang;
        }
    
        if($bayar_tabungan > 0){
            $this->db->insert('journal_details', [
                'journal_id'=>$journal_id,
                'account_id'=>$akun_tabungan,
                'debit'=>0,
                'kredit'=>$bayar_tabungan
            ]);
            $total_kredit += $bayar_tabungan;
        }
    
        // VALIDASI
        if(round($total_debit,2) !== round($total_kredit,2)){
            $this->db->trans_rollback();
            echo json_encode([
                'status'=>false,
                'message'=>'Jurnal tidak balance'
            ]);
            return;
        }
    
        // PAYMENT
        $this->db->insert('payments', [
            'invoice_id'=>$invoice_id,
            'tanggal'=>$tanggal_bayar,
            'jumlah'=>$total_bayar_input,
            'metode'=>'manual',
            'journal_id'=>$journal_id
        ]);
    
        // STATUS
        if($new_total_bayar >= $total_invoice){
            $status = 'paid';
            $sisa_setelah = 0;
        }elseif($new_total_bayar > 0){
            $status = 'partial';
        }else{
            $status = 'unpaid';
        }
    
        $this->db->where('id',$invoice_id)->update('invoices',[
            'total_bayar'=>$new_total_bayar,
            'sisa_piutang'=>$sisa_setelah,
            'status'=>$status,
            'updated_at'=>date('Y-m-d H:i:s'),
            'updated_by'=>$this->session->userdata('user_id')
        ]);
    
        $this->db->trans_complete();
        
        // =========================
        // RESPONSE
        // =========================
        if (!$this->db->trans_status()) {
            echo json_encode([
                'status' => false,
                'message' => 'Gagal menyelesaikan pembayaran'
            ]);
            return;
        }
    
        log_activity(
            'invoice',
            'create',
            'Melakukan pembayaran invoice ' . $invoice->no_invoice . ' untuk customer a.n ' . $customer->nama,
            'success'
        );
    
        echo json_encode([
            'status'=>true,
            'message'=>'Pembayaran berhasil',
            'sisa'=>$sisa_setelah
        ]);
    }

    // =========================
    // DELETE
    // =========================
    public function delete($id)
    {
        // Ambil invoice
        $invoice = $this->db->get_where('invoices', ['id' => $id])->row();

        if (!$invoice) {
            echo json_encode(['status'=>false,'message'=>'Invoice tidak ditemukan']);
            return;
        }

        // ❌ Cek detail
        $cekDetail = $this->db->where('invoice_id', $id)
                              ->count_all_results('invoice_details');

        if ($cekDetail > 0) {
            echo json_encode([
                'status'=>false,
                'message'=>'Invoice tidak bisa dihapus karena masih memiliki detail'
            ]);
            return;
        }

        if ($invoice->posted == 1) {
            echo json_encode([
                'status'=>false,
                'message'=>'Invoice sudah diposting, tidak bisa dihapus'
            ]);
            return;
        }

        // ❌ Cek sudah dibayar
        if (in_array($invoice->status, ['paid','partial'])) {
            echo json_encode([
                'status'=>false,
                'message'=>'Invoice sudah ada pembayaran, tidak bisa dihapus'
            ]);
            return;
        }

        // ✅ Hapus
        $this->db->delete('invoices', ['id'=>$id]);

        log_activity(
            'invoice',
            'delete',
            'Menghapus invoice ID ' . $id . ' - ' . $invoice->no_invoice,
            'success'
        );

        echo json_encode(['status'=>true]);
    }


    public function detail($id)
    {
        // GET customer_id
        $row = $this->db->select('customer_id')
            ->where('id',$id)
            ->get('invoices')
            ->row();
        
        $data['active_menu'] = "invoice_draft";
        $data['invoice_id'] = $id;
        $data['customer_id'] = $row ? $row->customer_id : null;

        $this->load->view('partials/header', $data);
        $this->load->view('invoices/detail', $data);
        $this->load->view('partials/footer');
    }


    public function get_invoice($id)
    {
        // ================= AMBIL INVOICE =================
        $this->db->select('invoices.*, customers.nama, customers.alamat, customers.telp, customers.email');
        $this->db->from('invoices');
        $this->db->join('customers', 'customers.id = invoices.customer_id');
        $this->db->where('invoices.id', $id);

        $data = $this->db->get()->row();

        if(!$data){
            echo json_encode(null);
            return;
        }

        // ================= AMBIL TUNGGAKAN =================
        $this->db->select_sum('sisa_piutang');
        $this->db->where('customer_id', $data->customer_id);
        $this->db->where('status !=', 'paid');
        $this->db->where('id !=', $id); // exclude invoice sekarang

        $tunggakan = $this->db->get('invoices')->row()->sisa_piutang ?? 0;

        // ================= MASUKKAN KE DATA =================
        $data->tunggakan = (int)$tunggakan;

        // ================= OUTPUT =================
        echo json_encode($data);
    }

    // =========================
    // GET ITEMS
    // =========================
    public function get_items($id)
    {
        $this->db->select('invoice_details.*, accounts.kode_akun, accounts.nama_akun, invoices.status');
        $this->db->from('invoice_details');
        $this->db->join('accounts', 'accounts.id = invoice_details.account_id', 'left');
        $this->db->join('invoices', 'invoices.id = invoice_details.invoice_id', 'left');
        $this->db->where('invoice_details.invoice_id', $id);
        $this->db->order_by('tanggal','ASC');
        $this->db->order_by('id','ASC');

        $data = $this->db->get()->result();

        echo json_encode($data);
    }

    // =========================
    // 🔥 CONFIG AKUN
    // =========================
    private $akun_persediaan = 21;
    private $akun_hpp        = 63;
    private $akun_piutang    = 19;
    
    // =========================
    // ADD ITEM - FIXED RESPONSE
    // =========================
    public function add_item()
    {
        $this->db->trans_begin();
    
        $invoice_id = $this->input->post('invoice_id');
        $tanggal    = $this->input->post('tanggal');
        $item_id    = $this->input->post('item_id');
        $nama_item  = $this->input->post('nama_item');
        $qty        = (float)$this->input->post('qty');
        $harga      = (float)$this->input->post('harga');
        $account_id = $this->input->post('account_id');
        $warehouse_id = $this->input->post('warehouse_id');
    
        $total_harga = $qty * $harga;
        $total_hpp   = 0;
        
        // jika di bayar cicilan
        $is_cicilan = $this->input->post('is_cicilan') ?? null;
        $tenor      = (int)$this->input->post('tenor') ?? 0;
    
        // =========================
        // VALIDASI & AMBIL ITEM
        // =========================
        if($item_id){
            $item = $this->db->get_where('items', ['id'=>$item_id])->row();
            if(!$item){
                echo json_encode(['status'=>false, 'message'=>'Item tidak ditemukan']);
                $this->db->trans_rollback();
                return;
            }
    
            $nama_item = $item->nama_barang;
    
            // cek stok
            $stok = $this->get_stok($item_id);
            if($stok < $qty){
                echo json_encode(['status'=>false, 'message'=>'Stok tidak cukup. Sisa: '.$stok]);
                $this->db->trans_rollback();
                return;
            }
    
            $total_hpp = $qty * $item->harga_beli;
        }
        
        // =========================
        // HANDLE CICILAN
        // =========================
        $harga_simpan   = $harga;
        $subtotal_simpan= $total_harga;
        $harga_asli     = $total_harga;
        
        $ket_cicilan_inv = '';
        $ket_cicilan_jr = '';
    
        if ($is_cicilan && $tenor > 0) {
    
            // harga per cicilan
            $harga_cicilan = round($total_harga / $tenor);
    
            $harga_simpan    = $harga_cicilan;
            $subtotal_simpan = $harga_cicilan;
            
            $ket_cicilan_inv    = ' ( Cicilan ke 1/' . $tenor . ' )';
            $ket_cicilan_jr     = ' ( Cicilan ' . $tenor . ' Periode )';
        }
    
        // =========================
        // INSERT DETAIL
        // =========================
        $insert_data = [
            'invoice_id'   => $invoice_id,
            'tanggal'      => $tanggal,
            'account_id'   => $account_id,
            'items_id'     => $item_id ?: null,
            'nama_item'    => $nama_item . $ket_cicilan_inv,
            'qty'          => $qty,
            'harga'        => $harga_simpan,
            'subtotal'     => $subtotal_simpan,
            'warehouse_id' => $warehouse_id,
            'keterangan'   => $this->input->post('keterangan'),
            'subtotal_asli' => $harga_asli,
            'is_cicilan'    => $is_cicilan ? 1 : 0
        ];
    
        $this->db->insert('invoice_details', $insert_data);
        $detail_id = $this->db->insert_id();
    
        // =========================
        // JURNAL + STOK
        // =========================
        if($this->input->post('account_id') != 70) {
            $this->generate_jurnal_item($detail_id, $ket_cicilan_jr);
        }
        $this->update_total($invoice_id);
        
        // ambil customer dari invoice
        $invoice = $this->db->get_where('invoices', ['id' => $invoice_id])->row();
        
        if ($is_cicilan && $tenor > 0) {
        
            // generate cicilan
            $this->generate_installments(
                $invoice_id,
                $detail_id,
                $invoice->customer_id,
                $total_harga,
                $tenor,
                $tanggal,
                $account_id,
                $item_id ?: null
            );
        }

        // ✅ RESPONSE KONSISTEN DENGAN JS
        if ($this->db->trans_status() === FALSE){
            $this->db->trans_rollback();
            echo json_encode(['status'=>false, 'message'=>'Transaksi gagal']);
        } else {
            $this->db->trans_commit();
    
            log_activity(
                'invoice',
                'add_item',
                'Tambah item invoice ID ' . $invoice_id . ' - ' . $nama_item,
                'success'
            );
            
            echo json_encode(['status'=>true, 'message'=>'Item berhasil ditambahkan']);
        }
    }
    
    // =========================
    // UPDATE ITEM - RESPONSE KONSISTEN
    // =========================
    public function update_item()
    {
        $this->db->trans_begin();
    
        $id = $this->input->post('id');
        $old = $this->db->get_where('invoice_details', ['id'=>$id])->row();
    
        if(!$old){
            echo json_encode(['status'=>false, 'message'=>'Item tidak ditemukan']);
            return;
        }
        
        $cek = $this->db->get_where('invoice_installments', [
            'invoice_detail_id' => $id
        ])->num_rows();
        
        if ($cek > 0) {
            echo json_encode([
                'status' => false,
                'message' => 'Item cicilan tidak bisa diubah. Hapus dan buat ulang.'
            ]);
            return;
        }
    
        // 🔥 REVERSE DATA LAMA
        $this->delete_jurnal_item($id);
        $this->delete_stok_item($id);
    
        // DATA BARU
        $item_id   = $this->input->post('item_id');
        $nama_item = $this->input->post('nama_item');
        $tanggal   = $this->input->post('tanggal');
    
        if($item_id){
            $item = $this->db->get_where('items', ['id'=>$item_id])->row();
            if($item){
                $nama_item = $item->nama_barang;
                $stok = $this->get_stok($item_id);
                $qty = (float)$this->input->post('qty');
                if($stok < $qty){
                    echo json_encode(['status'=>false, 'message'=>'Stok tidak cukup']);
                    return;
                }
            }
        }
    
        $qty   = (float)$this->input->post('qty');
        $harga = (float)$this->input->post('harga');
    
        // UPDATE
        $update_data = [
            'tanggal'      => $tanggal,
            'account_id'   => $this->input->post('account_id'),
            'items_id'     => $item_id ?: null,
            'nama_item'    => $nama_item,
            'qty'          => $qty,
            'harga'        => $harga,
            'subtotal'     => $qty * $harga,
            'warehouse_id' => $this->input->post('warehouse_id'),
            'keterangan'   => $this->input->post('keterangan')
        ];
    
        $this->db->where('id', $id)->update('invoice_details', $update_data);
    
        // GENERATE ULANG
        if($this->input->post('account_id') != 70) {
            $this->generate_jurnal_item($id);
        }
        $this->update_total($old->invoice_id);
    
        // ✅ RESPONSE KONSISTEN DENGAN JS
        if ($this->db->trans_status() === FALSE){
            $this->db->trans_rollback();
            echo json_encode(['status'=>false, 'message'=>'Update gagal']);
        } else {
            $this->db->trans_commit();
    
            log_activity(
                'invoice',
                'update_item',
                'Update item invoice detail ID ' . $id,
                'success'
            );
            
            echo json_encode(['status'=>true, 'message'=>'Item berhasil diupdate']);
        }
    }
    
    // =========================
    // DELETE ITEM - RESPONSE KONSISTEN
    // =========================
    public function delete_item($id)
    {
        $this->db->trans_begin();
    
        $d = $this->db->get_where('invoice_details', ['id'=>$id])->row();
    
        if(!$d){
            echo json_encode(['status'=>false, 'message'=>'Item tidak ditemukan']);
            return;
        }
        
        if($d->is_cicilan == 1) {
            $this->delete_invoice_installments($id, $d->source_cicilan_id);
        }
        // reverse stok & hapus
        $this->delete_jurnal_item($id);
        $this->delete_stok_item($id);
        $this->db->delete('invoice_details', ['id'=>$id]);
        $this->update_total($d->invoice_id);
    
        // ✅ RESPONSE KONSISTEN DENGAN JS
        if ($this->db->trans_status() === FALSE){
            $this->db->trans_rollback();
            echo json_encode(['status'=>false, 'message'=>'Hapus gagal']);
        } else {
            $this->db->trans_commit();
    
            log_activity(
                'invoice',
                'delete_item',
                'Hapus item invoice detail ID ' . $id,
                'success'
            );
    
            echo json_encode(['status'=>true, 'message'=>'Item berhasil dihapus']);
        }
    }

    // =========================
    // AMBIL DATA CICILAN
    // =========================
    public function get_cicilan($id) 
    {
        $cicilan_raw = $this->db->query("
            SELECT 
                ii.*,
                it.nama_barang
            FROM invoice_installments ii
            LEFT JOIN items it ON ii.item_id = it.id
            WHERE ii.customer_id = ?
            AND ii.status IN ('unpaid','partial')
            AND (ii.nominal - ii.paid_amount) > 0
            AND ii.is_billed = 0
            ORDER BY ii.invoice_detail_id, ii.angsuran_ke ASC
        ", [$id])->result();
    
        echo json_encode($cicilan_raw);
    }
    
    // public function save_cicilan()
    // {
    //     $cicilan_ids = $this->input->post('cicilan_id');
    
    //     if (empty($cicilan_ids)) {
    //         echo json_encode([
    //             'status' => false,
    //             'message' => 'Tidak ada data dipilih'
    //         ]);
    //         return;
    //     }
    
    //     $this->db->trans_start();
    
    //     foreach ($cicilan_ids as $id) {
    
    //         // ambil data cicilan
    //         $cicilan = $this->db->get_where('invoice_installments', [
    //             'id' => $id
    //         ])->row();
    
    //         if (!$cicilan) continue;
    
    //         $sisa = $cicilan->nominal - $cicilan->paid_amount;
    
    //         // insert ke invoice_details
    //         $this->db->insert('invoice_details', [
    //             'invoice_id'       => $cicilan->invoice_id,
    //             'customer_id'      => $cicilan->customer_id,
    //             'item_id'          => $cicilan->item_id,
    //             'qty'              => 1,
    //             'price'            => $sisa,
    //             'total'            => $sisa,
    //             'source_cicilan_id'=> $cicilan->id, // penting buat tracking
    //             'created_at'       => date('Y-m-d H:i:s')
    //         ]);
    
    //         // update status cicilan jadi billed
    //         $this->db->update('invoice_installments', [
    //             'is_billed' => 1
    //         ], ['id' => $id]);
    //     }
    
    //     $this->db->trans_complete();
    
    //     echo json_encode([
    //         'status' => $this->db->trans_status()
    //     ]);
    // }
    // =========================
    // HAPUS HELPER LAMA - TIDAK DIPAKAI LAGI
    // =========================
    // Hapus fungsi commit() & rollback() karena sudah inline
    
    private function generate_jurnal_item($id, $ket_cicilan_jr = null)
    {
        // $d = $this->db->get_where('invoice_details', ['id'=>$id])->row();
    
        // if(!$d) return;
        
        $d = $this->db
            ->select('
                invoice_details.*,
                customers.nama,
                invoices.no_invoice
            ')
            ->from('invoice_details')
            ->join('invoices', 'invoices.id = invoice_details.invoice_id')
            ->join('customers', 'customers.id = invoices.customer_id')
            ->where('invoice_details.id', $id)
            ->get()
            ->row();
        
        if(!$d) return;
    
        $total_hpp = 0;
    
        // =========================
        // 🔥 TENTUKAN NILAI JURNAL
        // =========================
        $nilai_jurnal = $d->subtotal;
    
        if (isset($d->is_cicilan) && $d->is_cicilan == 1) {
            $nilai_jurnal = $d->subtotal_asli ?? $d->subtotal;
        }
    
        // =========================
        // 🔥 STOK & HPP
        // =========================
        if($d->items_id){
    
            $item = $this->db->get_where('items',['id'=>$d->items_id])->row();
    
            if($item){
                $total_hpp = $item->harga_beli * $d->qty;
            }
    
            // stok keluar
            $this->db->insert('stock_logs', [
                'item_id'      => $d->items_id,
                'qty'          => $d->qty,
                'tipe'         => 'keluar',
                'ref_type'     => 'invoice_details',
                'ref_id'       => $id,
                'warehouse_id' => $d->warehouse_id,
                'keterangan'   => 'Penjualan ' . $item->nama_barang . ' kepada ' . $d->nama . ' - Invoice ' . $d->no_invoice . ' - Tgl ' . $d->tanggal
            ]);
    
            $this->update_item_stok($d->items_id);
        }        
        
        // =========================
        // 🔥 generate no_ref
        // =========================
        $no_ref = $this->generate_no_ref();
    
        // =========================
        // 🔥 JOURNAL HEADER
        // =========================
        $nama_item_jr = preg_replace('/\s*\(\s*Cicilan.*$/i', '', $d->nama_item) . $ket_cicilan_jr;
        $this->db->insert('journals', [
            'tanggal'    => $d->tanggal,
            'no_ref'     => $no_ref,
            'keterangan' => 'Penjualan '.$nama_item_jr,
            'ref_type'   => 'invoice_details',
            'ref_id'     => $id,
            'created_by' => $this->session->userdata('user_id')
        ]);
    
        $jid = $this->db->insert_id();
    
        // =========================
        // 🔥 PIUTANG (DEBIT)
        // =========================
        $this->db->insert('journal_details', [
            'journal_id' => $jid,
            'account_id' => $this->akun_piutang,
            'debit'      => $nilai_jurnal,
            'kredit'     => 0
        ]);
    
        // =========================
        // 🔥 PENDAPATAN (KREDIT)
        // =========================
        $this->db->insert('journal_details', [
            'journal_id' => $jid,
            'account_id' => $d->account_id,
            'debit'      => 0,
            'kredit'     => $nilai_jurnal
        ]);
    
        // =========================
        // 🔥 HPP & PERSEDIAAN
        // =========================
        if($total_hpp > 0){
    
            // HPP (debit)
            $this->db->insert('journal_details', [
                'journal_id' => $jid,
                'account_id' => $this->akun_hpp,
                'debit'      => $total_hpp,
                'kredit'     => 0
            ]);
    
            // Persediaan (kredit)
            $this->db->insert('journal_details', [
                'journal_id' => $jid,
                'account_id' => $this->akun_persediaan,
                'debit'      => 0,
                'kredit'     => $total_hpp
            ]);
        }
    }

    // =========================
    // 🔥 DELETE JURNAL
    // =========================
    private function delete_jurnal_item($id)
    {
        $d = $this->db->get_where('invoice_details', ['id'=>$id])->row();
    
        $j = $this->db->get_where('journals', [
            'ref_type'=>'invoice_details',
            'ref_id'=>$id
        ])->result();
    
        foreach($j as $row){
            $this->db->delete('journal_details', ['journal_id'=>$row->id]);
            $this->db->delete('journals', ['id'=>$row->id]);
        }
    
        if($d && $d->items_id){
            $this->update_item_stok($d->items_id); // ✅ BENAR
        }
    }

    // =========================
    // 🔥 DELETE STOK
    // =========================
    private function delete_stok_item($id)
    {
        $d = $this->db->get_where('invoice_details', ['id'=>$id])->row();
    
        $this->db->delete('stock_logs', [
            'ref_type'=>'invoice_details',
            'ref_id'=>$id
        ]);
    
        if($d && $d->items_id){
            $this->update_item_stok($d->items_id); // ✅ BENAR
        }
    }

    // =========================
    // 🔥 DELETE INVOICES INSTALLMENT
    // =========================
    private function delete_invoice_installments($invoice_detail_id,$source_cicilan_id)
    {
        $cek = $this->db
            ->where_in('status', ['paid', 'partial'])
            ->where('invoice_detail_id', $invoice_detail_id)
            ->count_all_results('invoice_installments');
    
        // kalau TIDAK ADA paid/partial → hapus
        if ($cek === 0) {
            $this->db->delete('invoice_installments', [
                'invoice_detail_id' => $invoice_detail_id
            ]);
        }
        
        if ($source_cicilan_id) {
            $this->db->update('invoice_installments', [
                'is_billed' => 0
            ], ['id' => $source_cicilan_id]);
        }
    }

    // =========================
    // 🔥 GET STOK
    // =========================
    private function get_stok($item_id)
    {
        return $this->db->query("
            SELECT COALESCE(SUM(qty * IF(tipe='masuk',1,-1)),0) as stok
            FROM stock_logs
            WHERE item_id = ?
        ", [$item_id])->row()->stok;
    }

    // =========================
    // ADD ITEM - FIXED HELPER
    // =========================
    private function commit()
    {
        if ($this->db->trans_status() === FALSE){
            $this->db->trans_rollback();
            echo json_encode(['status'=>false, 'message'=>'Transaksi gagal']);
        } else {
            $this->db->trans_commit();
            echo json_encode(['status'=>true, 'message'=>'Berhasil']);
        }
    }

    private function rollback($message)
    {
        $this->db->trans_rollback();
        echo json_encode(['status'=>false, 'message'=>$message]);
    }

    // =========================
    // UPDATE TOTAL
    // =========================
    private function update_total($invoice_id)
    {
        $this->db->select_sum('subtotal', 'total');
        $this->db->where('invoice_id', $invoice_id);
        $total = $this->db->get('invoice_details')->row()->total ?? 0;

        $this->db->where('id', $invoice_id)
                 ->update('invoices', ['total' => $total]);
    }

    // =========================
    // UPDATE TOTAL
    // =========================
    private function generate_no_ref()
    {
        $tanggal = date('Y-m-d');
        $prefix  = 'INV-'.date('Ymd').'-';

        // ambil nomor terakhir hari ini
        $last = $this->db->query("
            SELECT no_ref 
            FROM journals
            WHERE DATE(tanggal) = ?
            AND no_ref LIKE ?
            ORDER BY no_ref DESC
            LIMIT 1
        ", [$tanggal, $prefix.'%'])->row();

        if($last){
            $last_number = (int) substr($last->no_ref, -4);
            $next = $last_number + 1;
        } else {
            $next = 1;
        }

        return $prefix . str_pad($next, 4, '0', STR_PAD_LEFT);
    }

    // =========================
    // GET ACCOUNTS
    // =========================
    public function get_accounts()
    {
        $data = $this->db
            ->group_start()
                ->where('tipe', 'revenue')
                ->or_where('id', 70)
            ->group_end()
            ->order_by('kode_akun', 'ASC')
            ->get('accounts')
            ->result();
    
        echo json_encode($data);
    }

    public function get_accounts_assets()
    {
        $data = $this->db
            ->where_in('kode_akun', [101,102,207,201,202,203,204,205])
            ->order_by('kode_akun', 'ASC')
            ->get('accounts')
            ->result();

        echo json_encode($data);
    }

    public function check_items_by_account($account_id)
    {
        $exists = $this->db
            ->where('account_id', $account_id)
            ->limit(1)
            ->get('items')
            ->num_rows() > 0;

        echo json_encode([
            'has_item' => $exists
        ]);
    }

    public function get_items_by_wh_account($warehouse_id, $account_id)
    {
        $this->db->select('
            items.id,
            items.nama_barang,
            items.harga_jual,
            items.kode_detail,
            COALESCE(SUM(
                stock_logs.qty * IF(stock_logs.tipe="masuk",1,-1)
            ),0) as stok
        ');
        
        $this->db->where('status', 'active');
        $this->db->from('items');

        $this->db->join('stock_logs', 
            'stock_logs.item_id = items.id 
             AND stock_logs.warehouse_id = '.$this->db->escape($warehouse_id),
        'left');

        $this->db->where('items.account_id', $account_id);

        $this->db->group_by('items.id');
        
        // ✅ INI KUNCINYA
        $this->db->having('stok >', 0);


        $data = $this->db->get()->result();

        echo json_encode($data);
    }

    public function gudang_list()
    {
        echo json_encode(
            $this->db->get('warehouses')->result()
        );
    }

    public function get_payment($invoice_id)
    {
        $this->db->select('
            id,
            tanggal,
            jumlah,
            metode,
            created_at
        ');
        $this->db->from('payments');
        $this->db->where('invoice_id', $invoice_id);
        $this->db->order_by('id','DESC');

        $data = $this->db->get()->result();

        $result = [];

        $this->db->from('invoices');
        $this->db->where('invoices.id', $invoice_id);

        $invoice = $this->db->get()->row();

        foreach ($data as $row) {
            $result[] = [
                'id' => $row->id,
                'tanggal' => date('d-m-Y', strtotime($row->tanggal)),
                'jumlah' => 'Rp '.number_format($row->jumlah,0,',','.'),
                'metode' => $row->metode,
                'created_at' => date('d-m-Y H:i', strtotime($row->created_at))
            ];
        }

        echo json_encode([
            'data' => $result,
            'invoice' => $invoice
        ]);
    }

    // Update Stok Cache
    private function update_item_stok($item_id)
    {
        $stok = $this->db->query("
            SELECT COALESCE(SUM(qty * IF(tipe='masuk',1,-1)),0) as stok
            FROM stock_logs
            WHERE item_id = ?
        ", [$item_id])->row()->stok;

        $this->db->where('id', $item_id)
                 ->update('items', [
                     'stok' => $stok
                 ]);
    }
    
    
    private function generate_installments($invoice_id, $detail_id, $customer_id, $total, $tenor, $start_date, $account_id, $item_id = null)
    {
        $nominal = round($total / $tenor);
        $sisa = $total - ($nominal * $tenor);
    
        for ($i = 1; $i <= $tenor; $i++) {
    
            $tgl = date('Y-m-d', strtotime("+".($i-1)." month", strtotime($start_date)));
    
            $nilai = $nominal;
    
            if ($i == $tenor) {
                $nilai += $sisa;
            }
            
            $is_billed = ($i == 1) ? 1 : 0;
    
            $this->db->insert('invoice_installments', [
                'invoice_id'         => $invoice_id,
                'invoice_detail_id'  => $detail_id, // 🔥 relasi ke item
                'customer_id'        => $customer_id,
                'angsuran_ke'        => $i,
                'total_angsuran'     => $tenor,
                'jatuh_tempo'        => $tgl,
                'nominal'            => $nilai,
                'account_id'         => $account_id,
                'item_id'            => $item_id ?: null,
                'status'             => 'unpaid',
                'is_billed'          => $is_billed
            ]);
        }
    }
    
    public function save_cicilan()
    {
        $cicilan_ids = $this->input->post('cicilan_id');
        $invoice_id  = $this->input->post('invoice_id');
    
        if (empty($cicilan_ids)) {
            echo json_encode([
                'status' => false,
                'message' => 'Tidak ada data dipilih'
            ]);
            return;
        }
    
        $this->db->trans_start();
    
        foreach ($cicilan_ids as $id) {
    
            // =========================
            // AMBIL CICILAN
            // =========================
            $cicilan = $this->db->get_where('invoice_installments', [
                'id' => $id,
                'is_billed' => 0 // penting!
            ])->row();
    
            if (!$cicilan) continue;
    
            // =========================
            // CEK DUPLIKAT
            // =========================
            $cek = $this->db->get_where('invoice_details', [
                'source_cicilan_id' => $id
            ])->row();
    
            if ($cek) continue;
    
            $sisa = $cicilan->nominal - $cicilan->paid_amount;
    
            // =========================
            // AMBIL REFERENSI ITEM
            // =========================
            $inv_items = $this->db
                ->select('account_id, items_id, nama_item, keterangan, subtotal_asli, is_cicilan')
                ->where('id', $cicilan->invoice_detail_id)
                ->get('invoice_details')
                ->row();
    
            if(!$inv_items) continue;
    
            // =========================
            // FORMAT NAMA
            // =========================
            if($cicilan->paid_amount > 0){
                $priodecicilan = '( Sisa Cicilan ke ' . $cicilan->angsuran_ke . '/' . $cicilan->total_angsuran . ' )';
            } else {
                $priodecicilan = '( Cicilan ke ' . $cicilan->angsuran_ke . '/' . $cicilan->total_angsuran . ' )';
            }
    
            $nama_item = preg_replace(
                '/\s*\(\s*Cicilan.*$/i',
                '',
                $inv_items->nama_item
            ) . ' ' . $priodecicilan;
    
            // =========================
            // INSERT
            // =========================
            $this->db->insert('invoice_details', [
                'invoice_id'        => $invoice_id,
                'tanggal'           => $cicilan->jatuh_tempo,
                'account_id'        => $inv_items->account_id,
                'items_id'          => $inv_items->items_id ?: null,
                'nama_item'         => $nama_item,
                'qty'               => 1,
                'harga'             => $sisa,
                'subtotal'          => $sisa,
                'warehouse_id'      => null,
                'keterangan'        => $inv_items->keterangan,
                'subtotal_asli'     => $inv_items->subtotal_asli,
                'is_cicilan'        => $inv_items->is_cicilan,
                'source_cicilan_id' => $cicilan->id
            ]);
    
            // =========================
            // UPDATE STATUS
            // =========================
            $this->db->update('invoice_installments', [
                'is_billed' => 1
            ], ['id' => $id]);
        }
        
        $this->update_total($invoice_id);
    
        $this->db->trans_complete();
    
        echo json_encode([
            'status' => $this->db->trans_status()
        ]);
    }
}