<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Carbon\Carbon;
use App\Models\FabricationFormula;
use App\Models\FabricationFormulaItem;
use App\Models\FabricationOrder;
use App\Models\FabricationOrderMaterial;
use App\Models\ProductStock;
use App\Models\StockTransaction;
use App\Models\Product;
use App\Services\AccountingService;

class FabricationController extends Controller
{
    // ========================================================================
    // 1. MASTER RESEP (BOM)
    // ========================================================================
    public function getFormulas(Request $request)
    {
        $user = $request->user();
        $query = FabricationFormula::with(['resultProduct', 'items.materialProduct']);
        
        if ($user->role !== 'owner' && $user->role !== 'super_admin') {
            $query->where('branch_id', $user->branch_id);
        }

        return response()->json(['success' => true, 'data' => $query->get()]);
    }

    public function storeFormula(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id',
            'result_product_id' => 'required|exists:products,id',
            'result_quantity' => 'required|numeric|min:0.01',
            'name' => 'required|string',
            'labor_cost_estimate' => 'required|numeric|min:0',
            'overhead_cost_estimate' => 'required|numeric|min:0',
            'items' => 'required|array|min:1',
            'items.*.material_product_id' => 'required|exists:products,id',
            'items.*.quantity_needed' => 'required|numeric|min:0.01',
        ]);

        try {
            DB::transaction(function () use ($request, &$formula) {
                $formula = FabricationFormula::create([
                    'branch_id' => $request->branch_id,
                    'result_product_id' => $request->result_product_id,
                    'result_quantity' => $request->result_quantity,
                    'name' => $request->name,
                    'labor_cost_estimate' => $request->labor_cost_estimate,
                    'overhead_cost_estimate' => $request->overhead_cost_estimate,
                    'created_by' => $request->user()->id,
                ]);

                foreach ($request->items as $item) {
                    FabricationFormulaItem::create([
                        'fabrication_formula_id' => $formula->id,
                        'material_product_id' => $item['material_product_id'],
                        'quantity_needed' => $item['quantity_needed'],
                    ]);
                }
            });

            return response()->json(['success' => true, 'message' => 'Resep berhasil dibuat.', 'data' => $formula]);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }

    public function updateFormula(Request $request, $id)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id',
            'result_product_id' => 'required|exists:products,id',
            'result_quantity' => 'required|numeric|min:0.01',
            'name' => 'required|string',
            'labor_cost_estimate' => 'required|numeric|min:0',
            'overhead_cost_estimate' => 'required|numeric|min:0',
            'items' => 'required|array|min:1',
            'items.*.material_product_id' => 'required|exists:products,id',
            'items.*.quantity_needed' => 'required|numeric|min:0.01',
        ]);

        try {
            DB::transaction(function () use ($request, $id, &$formula) {
                // 1. Cari Resep berdasarkan ID
                $formula = FabricationFormula::findOrFail($id);

                // 2. Update Data Header Resep
                $formula->update([
                    'branch_id' => $request->branch_id,
                    'result_product_id' => $request->result_product_id,
                    'result_quantity' => $request->result_quantity,
                    'name' => $request->name,
                    'labor_cost_estimate' => $request->labor_cost_estimate,
                    'overhead_cost_estimate' => $request->overhead_cost_estimate,
                ]);

                // 3. Hapus semua komposisi bahan baku lama
                FabricationFormulaItem::where('fabrication_formula_id', $formula->id)->delete();

                // 4. Masukkan kembali komposisi bahan baku yang baru / sudah diedit
                foreach ($request->items as $item) {
                    FabricationFormulaItem::create([
                        'fabrication_formula_id' => $formula->id,
                        'material_product_id' => $item['material_product_id'],
                        'quantity_needed' => $item['quantity_needed'],
                    ]);
                }
            });

            return response()->json([
                'success' => true, 
                'message' => 'Resep berhasil diupdate.', 
                'data' => $formula
            ]);

        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return response()->json(['success' => false, 'message' => 'Data Resep tidak ditemukan.'], 404);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal mengupdate resep: ' . $e->getMessage()], 500);
        }
    }

    public function getProductsByType(Request $request)
    {
        $branchId = $request->query('branch_id', 1);
        
        // Ambil semua produk yang aktif
        $products = \App\Models\Product::where('is_active', 1)->get();

        return response()->json([
            'success' => true,
            'finished_goods' => $products->where('product_type', 'finished_good')->values(),
            
            // PERBAIKAN: Gabungkan raw_material dan consumable (bahan penolong) agar muncul di Dropdown
            'raw_materials'  => $products->whereIn('product_type', ['raw_material', 'consumable'])->values()
        ]);
    }

    // ========================================================================
    // 2. SURAT PERINTAH KERJA (SPK) / PRODUKSI
    // ========================================================================
    public function getOrders(Request $request)
    {
        $user = $request->user();
        
        // PERBAIKAN: Tambahkan 'formula.items.materialProduct' agar bahan baku ikut dikirim
        $query = FabricationOrder::with([
            'formula.resultProduct', 
            'formula.items.materialProduct', 
            'user'
        ]);
        
        if ($user->role !== 'owner' && $user->role !== 'super_admin') {
            $query->where('branch_id', $user->branch_id);
        }

        return response()->json(['success' => true, 'data' => $query->orderBy('created_at', 'desc')->get()]);
    }

    public function createOrder(Request $request)
    {
        $request->validate([
            'fabrication_formula_id' => 'required|exists:fabrication_formulas,id',
            'multiplier' => 'required|numeric|min:1', 
        ]);

        $user = $request->user();
        $formula = FabricationFormula::findOrFail($request->fabrication_formula_id);

        $spkNumber = 'FAB/' . strtoupper(substr($user->branch->code ?? 'PST', 0, 3)) . '/' . date('ym') . '/' . rand(1000, 9999);

        $order = FabricationOrder::create([
            'branch_id' => $formula->branch_id,
            'fabrication_formula_id' => $formula->id,
            'user_id' => $user->id,
            'spk_number' => $spkNumber,
            'multiplier' => $request->multiplier,
            'target_quantity' => $formula->result_quantity * $request->multiplier,
            'status' => 'processing',
        ]);

        return response()->json(['success' => true, 'message' => 'SPK Produksi berhasil dibuat.', 'data' => $order]);
    }

    // ========================================================================
    // 3. PENYELESAIAN SPK (INPUT AKTUAL & JURNAL OTOMATIS)
    // ========================================================================
    public function finishOrder($id, Request $request)
    {
        // Validasi input aktual dari frontend
        $request->validate([
            'actual_finished_qty' => 'required|numeric|min:0.0001',
            'materials' => 'required|array',
            'materials.*.material_product_id' => 'required|exists:products,id',
            'materials.*.actual_qty' => 'required|numeric|min:0',
        ]);

        $user = $request->user();
        
        try {
            DB::transaction(function () use ($id, $request, $user) {
                $order = FabricationOrder::with(['formula.resultProduct'])->lockForUpdate()->findOrFail($id);
                
                if ($order->status !== 'processing' && $order->status !== 'draft') {
                    throw new \Exception("SPK ini sudah selesai atau dibatalkan.");
                }

                $branchId = $order->branch_id;
                $multiplier = $order->multiplier;
                $formula = $order->formula;

                $totalMaterialCost = 0;

                // A. LOOPING BAHAN BAKU AKTUAL: POTONG STOK & HITUNG TOTAL BIAYA MATERIAL
                foreach ($request->materials as $item) {
                    $actualQtyUsed = (float) $item['actual_qty'];
                    $product = Product::findOrFail($item['material_product_id']);
                    
                    // Ambil HPP bahan baku saat ini
                    $hppMaterial = (isset($product->average_cost) && $product->average_cost > 0) ? $product->average_cost : ($product->buy_price ?? 0);
                    $totalItemCost = $hppMaterial * $actualQtyUsed;
                    $totalMaterialCost += $totalItemCost;

                    // Potong stok hanya jika aktual terpakai > 0
                    if ($actualQtyUsed > 0) {
                        $stock = ProductStock::firstOrCreate(
                            ['branch_id' => $branchId, 'product_id' => $product->id],
                            ['quantity' => 0]
                        );
                        
                        if ($stock->quantity < $actualQtyUsed) {
                            throw new \Exception("Stok Bahan Baku ({$product->name}) tidak mencukupi. Tersedia: {$stock->quantity}, Dibutuhkan: {$actualQtyUsed}");
                        }
                        $stock->decrement('quantity', $actualQtyUsed);

                        StockTransaction::create([
                            'branch_id' => $branchId,
                            'product_id' => $product->id,
                            'type' => 'fabrication_out',
                            'input_quantity' => $actualQtyUsed,
                            'input_unit' => $product->unit,
                            'actual_quantity' => $actualQtyUsed,
                            'user_id' => $user->id,
                            'note' => "Realisasi Produksi SPK: " . $order->spk_number,
                        ]);
                    }

                    // Hapus data material rencana, ganti dengan data aktual
                    FabricationOrderMaterial::updateOrCreate(
                        ['fabrication_order_id' => $order->id, 'material_product_id' => $product->id],
                        [
                            'quantity_used' => $actualQtyUsed,
                            'unit_price' => $hppMaterial,
                            'total_price' => $totalItemCost,
                        ]
                    );
                }

                // B. HITUNG BIAYA TENAGA KERJA & OVERHEAD (Sesuai SPK)
                $totalLaborCost = $formula->labor_cost_estimate * $multiplier;
                $totalOverheadCost = $formula->overhead_cost_estimate * $multiplier;
                
                // C. TOTAL BIAYA PRODUKSI
                $grandTotalCost = $totalMaterialCost + $totalLaborCost + $totalOverheadCost;

                // D. PENERIMAAN BARANG JADI AKTUAL
                $actualFinishedQty = (float) $request->actual_finished_qty;
                
                if ($actualFinishedQty <= 0) {
                    throw new \Exception("Hasil produksi tidak valid (0). Pastikan input hasil produksi telah diisi dengan benar.");
                }
                
                $resultProduct = $formula->resultProduct;

                $stockResult = ProductStock::firstOrCreate(
                    ['branch_id' => $branchId, 'product_id' => $resultProduct->id],
                    ['quantity' => 0]
                );
                $stockResult->increment('quantity', $actualFinishedQty);

                // HITUNG HPP BARU: Total Biaya Aktual / Jumlah Barang Jadi Aktual
                $newHppPerUnit = $grandTotalCost / $actualFinishedQty;
                $resultProduct->update(['average_cost' => $newHppPerUnit]);

                StockTransaction::create([
                    'branch_id' => $branchId,
                    'product_id' => $resultProduct->id,
                    'type' => 'fabrication_in',
                    'input_quantity' => $actualFinishedQty,
                    'input_unit' => $resultProduct->unit,
                    'actual_quantity' => $actualFinishedQty,
                    'user_id' => $user->id,
                    'note' => "Hasil Aktual Produksi SPK: " . $order->spk_number,
                ]);

                // E. UPDATE STATUS SPK DENGAN DATA AKTUAL
                $order->update([
                    'status' => 'completed',
                    'actual_target_quantity' => $actualFinishedQty, 
                    'total_material_cost' => $totalMaterialCost,
                    'total_labor_cost' => $totalLaborCost,
                    'total_overhead_cost' => $totalOverheadCost,
                    'grand_total_cost' => $grandTotalCost,
                    'completed_at' => Carbon::now()
                ]);

                // F. PENJURNALAN AKUNTANSI
                $akunPersediaan = AccountingService::getAccountId('persediaan_barang');
                $akunBTKLDibebankan = AccountingService::getAccountId('btkl_dibebankan'); 
                $akunBOPDibebankan = AccountingService::getAccountId('bop_dibebankan');   

                if (!$akunPersediaan) throw new \Exception("Master Akun: 'persediaan_barang' belum dipetakan.");

                $journalItems = [];
                // Persediaan Barang Jadi Bertambah (Debit)
                $journalItems[] = ['account_id' => $akunPersediaan, 'debit' => $grandTotalCost, 'credit' => 0];
                // Persediaan Bahan Baku Berkurang (Kredit)
                $journalItems[] = ['account_id' => $akunPersediaan, 'debit' => 0, 'credit' => $totalMaterialCost];
                
                if ($totalLaborCost > 0 && $akunBTKLDibebankan) {
                    $journalItems[] = ['account_id' => $akunBTKLDibebankan, 'debit' => 0, 'credit' => $totalLaborCost];
                }
                
                if ($totalOverheadCost > 0 && $akunBOPDibebankan) {
                    $journalItems[] = ['account_id' => $akunBOPDibebankan, 'debit' => 0, 'credit' => $totalOverheadCost];
                }

                AccountingService::log([
                    'branch_id'   => $branchId,
                    'entry_date'  => Carbon::now()->toDateString(),
                    'description' => "Penyelesaian Produksi Aktual - " . $order->spk_number,
                    'reference'   => $order->spk_number,
                    'source_type' => 'FABRICATION_FINISH',
                    'user_id'     => $user->id,
                    'items'       => $journalItems
                ]);
            });

            return response()->json(['success' => true, 'message' => 'Realisasi SPK Berhasil. HPP telah dihitung ulang berdasarkan efisiensi aktual.']);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal menyelesaikan SPK: ' . $e->getMessage()], 400);
        }
    }

    // ========================================================================
    // 4. UNPOST SPK (Buka Kunci & Tarik Mundur Transaksi)
    // ========================================================================
    public function unpostOrder($id, Request $request)
    {
        try {
            DB::transaction(function () use ($id, $request) {
                
                $order = FabricationOrder::with(['materialsUsed', 'formula.resultProduct'])->lockForUpdate()->findOrFail($id);

                if ($order->status !== 'completed') {
                    throw new \Exception("Hanya SPK berstatus Selesai yang dapat di-Unpost.");
                }

                $branchId = $order->branch_id;
                $actualFinishedQty = $order->actual_target_quantity ?? $order->target_quantity;
                $resultProduct = $order->formula->resultProduct;

                // A. VALIDASI KEAMANAN: Pastikan Stok Barang Jadi masih mencukupi untuk ditarik mundur
                $stockResult = ProductStock::where('branch_id', $branchId)->where('product_id', $resultProduct->id)->first();
                if (!$stockResult || $stockResult->quantity < $actualFinishedQty) {
                    throw new \Exception("UNPOST DITOLAK: Stok Barang Jadi ({$resultProduct->name}) saat ini ({$stockResult->quantity}) kurang dari hasil produksi SPK ini ({$actualFinishedQty}). Sebagian barang sudah terjual atau dipindahkan.");
                }

                // B. TARIK MUNDUR STOK BARANG JADI (Dikurangi)
                $stockResult->decrement('quantity', $actualFinishedQty);

                // C. KEMBALIKAN STOK BAHAN BAKU (Ditambah kembali)
                foreach ($order->materialsUsed as $materialRow) {
                    $actualQtyUsed = $materialRow->quantity_used;
                    if ($actualQtyUsed > 0) {
                        $stockMaterial = ProductStock::firstOrCreate(
                            ['branch_id' => $branchId, 'product_id' => $materialRow->material_product_id],
                            ['quantity' => 0]
                        );
                        $stockMaterial->increment('quantity', $actualQtyUsed);
                    }
                }

                // D. HAPUS RIWAYAT MUTASI STOK
                StockTransaction::where('note', 'LIKE', "%{$order->spk_number}%")->delete();

                // E. HAPUS JURNAL AKUNTANSI 
                $journalEntry = DB::table('journal_entries')
                    ->where('reference', $order->spk_number)
                    ->first();
                
                if ($journalEntry) {
                    DB::table('journal_items')
                        ->where('journal_entry_id', $journalEntry->id)
                        ->delete();

                    DB::table('journal_entries')
                        ->where('id', $journalEntry->id)
                        ->delete();
                }

                // F. KEMBALIKAN STATUS SPK KE PROCESSING & RESET NILAI AKTUAL
                $order->update([
                    'status' => 'processing',
                    'actual_target_quantity' => 0,
                    'total_material_cost' => 0,
                    'total_labor_cost' => 0,
                    'total_overhead_cost' => 0,
                    'grand_total_cost' => 0,
                    'completed_at' => null
                ]);
            });

            return response()->json(['success' => true, 'message' => 'SPK berhasil di-Unpost (Buka Kunci). Stok fisik dan Jurnal Akuntansi telah dikembalikan ke kondisi semula.']);
            
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 400);
        }
    }

    // ========================================================================
    // 5. VOID / BATALKAN SPK (Hanya bisa jika status Processing/Draft)
    // ========================================================================
    public function cancelOrder($id, Request $request)
    {
        try {
            $order = FabricationOrder::findOrFail($id);

            // Cegah pembatalan jika sudah selesai
            if ($order->status === 'completed') {
                return response()->json(['success' => false, 'message' => 'SPK sudah selesai dieksekusi. Lakukan Unpost (Buka Kunci) terlebih dahulu jika ingin membatalkannya.'], 400);
            }

            if ($order->status === 'void') { 
                return response()->json(['success' => false, 'message' => 'SPK ini sudah dalam status Dibatalkan.'], 400);
            }

            // Eksekusi Pembatalan
            $order->update([
                'status' => 'void' 
            ]);

            return response()->json(['success' => true, 'message' => 'SPK berhasil Dibatalkan (Void).']);
            
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal membatalkan SPK: ' . $e->getMessage()], 500);
        }
    }

    // ========================================================================
    // 4. LAPORAN PRODUKSI & ANALISA HPP (REPORTING)
    // ========================================================================
    public function getReport(Request $request)
    {
        $user = $request->user();
        $startDate = $request->query('start_date', Carbon::now()->startOfMonth()->toDateString());
        $endDate = $request->query('end_date', Carbon::now()->endOfMonth()->toDateString());
        
        // PERBAIKAN: Menambahkan 'materialsUsed.materialProduct' untuk fitur Drill-down HPP
        $query = FabricationOrder::with([
                'formula.resultProduct', 
                'user',
                'materialsUsed.materialProduct' // <--- Relasi Detail Material Aktual
            ])
            ->where('status', 'completed')
            ->whereDate('completed_at', '>=', $startDate)
            ->whereDate('completed_at', '<=', $endDate);
            
        if ($user->role !== 'owner' && $user->role !== 'super_admin') {
            $query->where('branch_id', $user->branch_id);
        } elseif ($request->has('branch_id') && !empty($request->branch_id) && $request->branch_id !== 'all') {
            $query->where('branch_id', $request->branch_id);
        }

        $orders = $query->orderBy('completed_at', 'desc')->get()->map(function($order) {
            // Gunakan actual_target_quantity sebagai sumber kebenaran (Source of Truth)
            $order->display_qty = $order->actual_target_quantity > 0 ? $order->actual_target_quantity : $order->target_quantity;
            return $order;
        });

        $summary = [
            'total_spk' => $orders->count(),
            'total_material' => $orders->sum('total_material_cost'),
            'total_labor' => $orders->sum('total_labor_cost'),
            'total_overhead' => $orders->sum('total_overhead_cost'),
            'grand_total_hpp' => $orders->sum('grand_total_cost'),
        ];

        return response()->json([
            'success' => true, 
            'summary' => $summary,
            'data' => $orders 
        ]);
    }

    // ========================================================================
    // 5. REKONSILIASI VARIANS (TUTUP BUKU PABRIKASI BULANAN)
    // ========================================================================
    public function closeVariance(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id',
            'month' => 'required|integer|min:1|max:12',
            'year' => 'required|integer|min:2000|max:2100',
            'actual_labor_cost' => 'required|numeric|min:0',
            'actual_overhead_cost' => 'required|numeric|min:0',
        ]);

        $user = $request->user();
        
        if ($user->role !== 'owner' && $user->role !== 'super_admin') {
            if ($user->branch_id != $request->branch_id) {
                return response()->json(['success' => false, 'message' => 'Anda tidak memiliki akses ke cabang ini.'], 403);
            }
        }

        try {
            $result = \App\Services\AccountingService::closeMonthlyVariance(
                $request->branch_id,
                $request->month,
                $request->year,
                $request->actual_labor_cost,
                $request->actual_overhead_cost
            );

            return response()->json($result);
        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => 'Gagal memproses rekonsiliasi: ' . $e->getMessage()], 500);
        }
    }

    // ========================================================================
    // 6. AMBIL DATA BIAYA AKTUAL DARI BUKU BESAR UNTUK REKONSILIASI
    // ========================================================================
    public function getActualCosts(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id',
            'month' => 'required|integer|min:1|max:12',
            'year' => 'required|integer|min:2000|max:2100',
        ]);

        try {
            // PERBAIKAN: Menggunakan akun 5001 (Biaya Upah Harian Pabrik) agar terpisah dari gaji non-pabrik
            $akunGajiId = \App\Models\Account::where('code', '5001')->value('id');
            $akunListrikId = \App\Models\Account::where('code', '6211')->value('id');

            if (!$akunGajiId || !$akunListrikId) {
                throw new \Exception("Akun Biaya Upah Pabrik (5001) atau Biaya Listrik (6211) tidak ditemukan di master data akun.");
            }

            // Hitung Total Pengeluaran Aktual dari mutasi Debit Buku Besar
            $actualLabor = DB::table('journal_items')
                ->join('journal_entries', 'journal_items.journal_entry_id', '=', 'journal_entries.id')
                ->where('journal_entries.branch_id', $request->branch_id)
                ->whereMonth('journal_entries.entry_date', $request->month)
                ->whereYear('journal_entries.entry_date', $request->year)
                ->where('journal_items.account_id', $akunGajiId)
                ->select(DB::raw('SUM(debit) - SUM(credit) as total'))
                ->value('total');

            $actualOverhead = DB::table('journal_items')
                ->join('journal_entries', 'journal_items.journal_entry_id', '=', 'journal_entries.id')
                ->where('journal_entries.branch_id', $request->branch_id)
                ->whereMonth('journal_entries.entry_date', $request->month)
                ->whereYear('journal_entries.entry_date', $request->year)
                ->where('journal_items.account_id', $akunListrikId)
                ->select(DB::raw('SUM(debit) - SUM(credit) as total'))
                ->value('total');

            return response()->json([
                'success' => true,
                'actual_labor_cost' => max(0, (float) $actualLabor),
                'actual_overhead_cost' => max(0, (float) $actualOverhead),
            ]);

        } catch (\Exception $e) {
            return response()->json(['success' => false, 'message' => $e->getMessage()], 500);
        }
    }
}