<?php

namespace App\Models;

use CodeIgniter\Model;

class ProduksiModel extends Model
{
    protected $table          = 'tb_produksi';
    protected $primaryKey     = 'id_produksi';
    protected $useTimestamps  = true;
    protected $useSoftDeletes = true;
    protected $dateFormat     = 'datetime';

    protected $allowedFields = [
        'kode_produksi',
        'id_produk',
        'id_resep',
        'jumlah_produksi',
        'tanggal_produksi',
        'status_produksi',
        'biaya_tenaga',
        'biaya_lain',
        'total_biaya_bahan',
        'total_biaya',
        'hpp_per_unit',
        'catatan_produksi',
        'diselesaikan_oleh',
    ];

    // ── Generate kode produksi ───────────────────────────────────────
    public function generateKode(): string
    {
        $prefix = 'PRD-' . date('Ymd') . '-';
        $last   = $this->db->table('tb_produksi')
            ->like('kode_produksi', $prefix, 'after')
            ->orderBy('id_produksi', 'DESC')
            ->limit(1)
            ->get()->getRow();

        $seq = 1;
        if ($last) {
            $parts = explode('-', $last->kode_produksi);
            $seq   = (int) end($parts) + 1;
        }

        return $prefix . str_pad($seq, 3, '0', STR_PAD_LEFT);
    }

    // ── Daftar resep untuk form produksi ────────────────────────────
    // Sekarang join ke tb_detail_resep (bukan langsung tb_resep per bahan)
    public function getResepList(): array
    {
        $headers = $this->db->table('tb_resep r')
            ->select('
                r.id_resep,
                r.nama_resep,
                r.id_produk,
                r.catatan_resep,
                p.nama_produk,
                p.kode_produk,
                p.stok_produk,
                p.harga_produk
            ')
            ->join('tb_produk p', 'p.id_produk = r.id_produk', 'left')
            ->orderBy('r.nama_resep', 'ASC')
            ->get()->getResultArray();

        foreach ($headers as &$h) {
            $h['bahan'] = $this->db->table('tb_detail_resep d')
                ->select('d.id_bahan, d.jumlah_bahan, b.nama_bahan, b.satuan_bahan, b.stok_bahan, b.harga_bahan')
                ->join('tb_bahan b', 'b.id_bahan = d.id_bahan', 'left')
                ->where('d.id_resep', $h['id_resep'])
                ->get()->getResultArray();
        }

        return array_values($headers);
    }

    // ── List produksi ────────────────────────────────────────────────
    public function getList(): array
    {
        $rows = $this->db->table('tb_produksi p')
            ->select('
                p.id_produksi,
                p.kode_produksi,
                p.tanggal_produksi,
                p.status_produksi,
                p.jumlah_produksi,
                p.catatan_produksi,
                p.total_biaya_bahan,
                p.hpp_per_unit,
                pr.kode_produk,
                pr.nama_produk,
                pr.stok_produk,
                r.nama_resep
            ')
            ->join('tb_produk pr', 'pr.id_produk = p.id_produk')
            ->join('tb_resep r', 'r.id_resep = p.id_resep', 'left')
            ->where('p.deleted_at IS NULL')
            ->orderBy('p.id_produksi', 'DESC')
            ->get()->getResultArray();

        foreach ($rows as &$row) {
            $row['bahan'] = $this->db->table('tb_detail_produksi dp')
                ->select('dp.jumlah_total, b.nama_bahan, b.satuan_bahan')
                ->join('tb_bahan b', 'b.id_bahan = dp.id_bahan')
                ->where('dp.id_produksi', $row['id_produksi'])
                ->get()->getResultArray();
        }

        return $rows;
    }

    // ── Summary stats ────────────────────────────────────────────────
    public function getSummary(): array
    {
        $bulan = date('Y-m');

        return [
            'total'      => $this->db->table('tb_produksi')->where('deleted_at IS NULL')->countAllResults(),
            'selesai'    => $this->db->table('tb_produksi')->where('status_produksi', 'selesai')->where('deleted_at IS NULL')->countAllResults(),
            'dibatalkan' => $this->db->table('tb_produksi')->where('status_produksi', 'batal')->where('deleted_at IS NULL')->countAllResults(),
            'bulan_ini'  => $this->db->table('tb_produksi')
                ->where('deleted_at IS NULL')
                ->where("DATE_FORMAT(tanggal_produksi,'%Y-%m')", $bulan)
                ->countAllResults(),
        ];
    }

    // ── SIMPAN PRODUKSI ──────────────────────────────────────────────
    // Bahan diambil dari tb_detail_resep (bukan tb_resep per bahan)
    public function simpan(array $data): array
    {
        $db  = $this->db;
        $now = date('Y-m-d H:i:s');

        // Ambil header resep
        $idResepInput = $data['id_resep'] ?? null;
        $namaResep    = $data['nama_resep'] ?? null;

        // Cari id_resep — bisa dari id langsung atau nama_resep
        if ($idResepInput) {
            $resepHeader = $db->table('tb_resep')->where('id_resep', $idResepInput)->get()->getRowArray();
        } elseif ($namaResep) {
            $resepHeader = $db->table('tb_resep')->where('nama_resep', $namaResep)->get()->getRowArray();
        } else {
            return ['success' => false, 'error' => 'Resep tidak valid.'];
        }

        if (!$resepHeader) {
            return ['success' => false, 'error' => 'Resep tidak ditemukan.'];
        }

        // Ambil bahan dari tb_detail_resep (bukan tb_resep)
        $bahanResep = $db->table('tb_detail_resep d')
            ->select('d.id_bahan, d.jumlah_bahan, b.harga_bahan, b.stok_bahan, b.nama_bahan, b.satuan_bahan')
            ->join('tb_bahan b', 'b.id_bahan = d.id_bahan')
            ->where('d.id_resep', $resepHeader['id_resep'])
            ->get()->getResultArray();

        if (empty($bahanResep)) {
            return ['success' => false, 'error' => 'Resep tidak memiliki bahan.'];
        }

        // Validasi stok
        foreach ($bahanResep as $b) {
            $kebutuhan = (float) $b['jumlah_bahan'];
            if ((float) $b['stok_bahan'] < $kebutuhan) {
                return [
                    'success' => false,
                    'error'   => "Stok bahan \"{$b['nama_bahan']}\" tidak cukup. "
                        . "Dibutuhkan: {$kebutuhan} {$b['satuan_bahan']}, "
                        . "tersedia: {$b['stok_bahan']} {$b['satuan_bahan']}.",
                ];
            }
        }

        $idResep  = $resepHeader['id_resep'];
        $idProduk = (int) ($data['id_produk'] ?? $resepHeader['id_produk']);
        $jumlah   = (int) $data['jumlah_produksi'];
        $kode     = $this->generateKode();

        // Hitung biaya bahan
        $totalBiayaBahan = 0;
        foreach ($bahanResep as $b) {
            $totalBiayaBahan += (float) $b['harga_bahan'] * (float) $b['jumlah_bahan'];
        }
        $hppPerUnit = $jumlah > 0 ? round($totalBiayaBahan / $jumlah, 2) : 0;

        $db->transBegin();

        try {
            // 1. Insert header produksi
            $db->table('tb_produksi')->insert([
                'kode_produksi'     => $kode,
                'id_produk'         => $idProduk,
                'id_resep'          => $idResep,
                'jumlah_produksi'   => $jumlah,
                'tanggal_produksi'  => $data['tanggal_produksi'],
                'status_produksi'   => 'selesai',
                'catatan_produksi'  => $data['catatan_produksi'] ?? null,
                'biaya_tenaga'      => 0,
                'biaya_lain'        => 0,
                'total_biaya_bahan' => $totalBiayaBahan,
                'total_biaya'       => $totalBiayaBahan,
                'hpp_per_unit'      => $hppPerUnit,
                'created_at'        => $now,
                'updated_at'        => $now,
            ]);

            $idProduksi = $db->insertID();
            if (!$idProduksi) throw new \RuntimeException('Insert tb_produksi gagal.');

            // 2. Insert detail + kurangi stok bahan
            foreach ($bahanResep as $b) {
                $jumlahBahan = (float) $b['jumlah_bahan'];
                $harga       = (float) $b['harga_bahan'];

                $db->table('tb_detail_produksi')->insert([
                    'id_produksi'        => $idProduksi,
                    'id_bahan'           => $b['id_bahan'],
                    'jumlah_per_batch'   => $jumlahBahan,
                    'jumlah_total'       => $jumlahBahan,
                    'harga_satuan_bahan' => $harga,
                    'subtotal_bahan'     => $harga * $jumlahBahan,
                    'sudah_dikurangi'    => 1,
                    'created_at'         => $now,
                    'updated_at'         => $now,
                ]);

                $db->table('tb_bahan')
                    ->where('id_bahan', $b['id_bahan'])
                    ->set('stok_bahan', "GREATEST(stok_bahan - {$jumlahBahan}, 0)", false)
                    ->set('updated_at', $now)
                    ->update();
            }

            // 3. Tambah stok produk
            $db->table('tb_produk')
                ->where('id_produk', $idProduk)
                ->set('stok_produk', "stok_produk + {$jumlah}", false)
                ->set('updated_at', $now)
                ->update();

            // 4. Log stok produk masuk
            if ($db->tableExists('tb_stok_produk_log')) {
                $db->table('tb_stok_produk_log')->insert([
                    'id_produk'                  => $idProduk,
                    'tanggal_stok_produk_log'    => date('Y-m-d'),
                    'tipe_stok_produk_log'        => 'masuk',
                    'jumlah_stok_produk_log'     => $jumlah,
                    'keterangan_stok_produk_log' => 'Produksi: ' . $kode,
                    'created_at'                 => $now,
                ]);
            }

            // 5. Log penggunaan bahan
            if ($db->tableExists('tb_penggunaan_bahan')) {
                foreach ($bahanResep as $b) {
                    $db->table('tb_penggunaan_bahan')->insert([
                        'id_bahan'             => $b['id_bahan'],
                        'tanggal_penggunaan'   => $data['tanggal_produksi'],
                        'jumlah_penggunaan'    => (float) $b['jumlah_bahan'],
                        'keperluan_penggunaan' => 'Produksi: ' . $kode,
                        'catatan_penggunaan'   => 'Produk id=' . $idProduk . ', batch=' . $jumlah,
                        'created_at'           => $now,
                        'updated_at'           => $now,
                    ]);
                }
            }

            $db->transCommit();

            return [
                'success' => true,
                'message' => "Produksi {$kode} berhasil! Stok bahan berkurang sesuai resep & stok produk bertambah {$jumlah} kemasan.",
                'kode'    => $kode,
            ];

        } catch (\Throwable $e) {
            $db->transRollback();
            log_message('error', '[ProduksiModel::simpan] ' . $e->getMessage());
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }

    // ── BATALKAN PRODUKSI ────────────────────────────────────────────
    public function batalkan(int $id): array
    {
        $db = $this->db;

        $produksi = $db->table('tb_produksi')
            ->where('id_produksi', $id)
            ->where('status_produksi', 'selesai')
            ->where('deleted_at IS NULL')
            ->get()->getRow();

        if (!$produksi) {
            return ['success' => false, 'error' => 'Produksi tidak ditemukan atau sudah dibatalkan.'];
        }

        $now = date('Y-m-d H:i:s');
        $db->transBegin();

        try {
            $details = $db->table('tb_detail_produksi')
                ->where('id_produksi', $id)
                ->where('sudah_dikurangi', 1)
                ->get()->getResultArray();

            foreach ($details as $d) {
                $db->table('tb_bahan')
                    ->where('id_bahan', $d['id_bahan'])
                    ->set('stok_bahan', "stok_bahan + {$d['jumlah_total']}", false)
                    ->set('updated_at', $now)
                    ->update();
            }

            $db->table('tb_produk')
                ->where('id_produk', $produksi->id_produk)
                ->set('stok_produk', "GREATEST(stok_produk - {$produksi->jumlah_produksi}, 0)", false)
                ->set('updated_at', $now)
                ->update();

            if ($db->tableExists('tb_stok_produk_log')) {
                $db->table('tb_stok_produk_log')->insert([
                    'id_produk'                  => $produksi->id_produk,
                    'tanggal_stok_produk_log'    => date('Y-m-d'),
                    'tipe_stok_produk_log'        => 'keluar',
                    'jumlah_stok_produk_log'     => $produksi->jumlah_produksi,
                    'keterangan_stok_produk_log' => 'Batalkan produksi: ' . $produksi->kode_produksi,
                    'created_at'                 => $now,
                ]);
            }

            $db->table('tb_produksi')->where('id_produksi', $id)->update([
                'status_produksi' => 'batal',
                'updated_at'      => $now,
            ]);

            $db->table('tb_detail_produksi')->where('id_produksi', $id)->update([
                'sudah_dikurangi' => 0,
                'updated_at'      => $now,
            ]);

            $db->transCommit();

            return [
                'success' => true,
                'message' => "Produksi {$produksi->kode_produksi} dibatalkan. Stok bahan dikembalikan.",
            ];

        } catch (\Throwable $e) {
            $db->transRollback();
            log_message('error', '[ProduksiModel::batalkan] ' . $e->getMessage());
            return ['success' => false, 'error' => $e->getMessage()];
        }
    }
}