<?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\Services\AccountingService; 

class PurchasingController extends Controller
{
    /**
     * ========================================================================
     * 1. MENGAMBIL DAFTAR DOKUMEN PEMBELIAN (DILENGKAPI AUTO-HEAL)
     * ========================================================================
     */
    public function index(Request $request)
    {
        $user = $request->user();

        // Auto-heal zombie POs
        $zombiePos = DB::table('purchases')
            ->where('receipt_status', '!=', 'none')
            ->whereNotIn('id', function($query) {
                $query->select('purchase_id')->from('purchase_receipts');
            })
            ->get();

        foreach ($zombiePos as $zpo) {
            DB::table('purchase_items')->where('purchase_id', $zpo->id)->update(['qty_received' => 0]);
            DB::table('purchases')->where('id', $zpo->id)->update([
                'receipt_status' => 'none',
                'status'         => 'draft_po'
            ]);
        }

        $query = DB::table('purchases')
            ->join('suppliers', 'purchases.supplier_id', '=', 'suppliers.id')
            ->join('branches', 'purchases.branch_id', '=', 'branches.id')
            ->select(
                'purchases.*',
                'suppliers.name as supplier_name',
                'branches.name as branch_name'
            )
            // Menyembunyikan data Saldo Awal Hutang agar tidak masuk ke daftar PO
            ->where(function($q) {
                $q->where('purchases.is_initial_debt', false)
                  ->orWhereNull('purchases.is_initial_debt');
            })
            ->orderBy('purchases.created_at', 'desc');

        // PERBAIKAN ENTERPRISE: Isolasi Mutlak Data Cabang
        if ($user && $user->role !== 'owner') {
            $query->where('purchases.branch_id', $user->branch_id);
        } else {
            if ($request->has('branch_id') && $request->branch_id !== 'all') {
                $query->where('purchases.branch_id', $request->branch_id);
            }
        }

        if ($request->has('status') && $request->status !== 'all') {
            $query->where('purchases.status', $request->status);
        }

        $purchases = $query->get();

        if ($purchases->isNotEmpty()) {
            $purchaseIds = $purchases->pluck('id')->toArray();
            
            $items = DB::table('purchase_items')
                ->join('products', 'purchase_items.product_id', '=', 'products.id')
                ->whereIn('purchase_items.purchase_id', $purchaseIds)
                ->select(
                    'purchase_items.*',
                    'products.name as product_name',
                    'products.variant_name',
                    'products.sku as product_code'
                )
                ->get();

            foreach ($purchases as $purchase) {
                $purchase->items = $items->where('purchase_id', $purchase->id)->values()->toArray();
            }
        }

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

    /**
     * ========================================================================
     * 2. MEMBUAT PURCHASE ORDER (PO) BARU + LOGIKA UANG MUKA (DP)
     * ========================================================================
     */
    public function storePo(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|integer',
            'supplier_id' => 'required|integer',
            'po_date' => 'required|date',
            'tax_type' => 'required|in:non,include,exclude',
            'payment_method' => 'required|in:cash,credit',
            'items' => 'required|array|min:1',
            'dp_amount' => 'nullable|numeric|min:0',
            'dp_account_id' => 'nullable|required_if:dp_amount,>,0|integer'
        ]);

        $user = $request->user();
        
        // PERBAIKAN ENTERPRISE: Cegah Input Silang Cabang
        $branchId = ($user && $user->role !== 'owner') ? $user->branch_id : $request->branch_id;

        DB::beginTransaction();
        try {
            $dpAmount = (float) ($request->dp_amount ?? 0);

            // PERBAIKAN ENTERPRISE: Validasi Mapping Rekening Cabang Berlaku Universal
            // Menjamin DP masuk ke rekening yang secara resmi dipetakan untuk cabang tujuan
            if ($dpAmount > 0) {
                $isMapped = DB::table('branch_accounts')
                    ->where('branch_id', $branchId)
                    ->where('account_id', $request->dp_account_id)
                    ->where('is_active', 1)
                    ->exists();

                if (!$isMapped) {
                    throw new \Exception("Akses ditolak: Rekening pembayaran DP yang dipilih tidak terdaftar/dipetakan untuk Cabang tersebut.");
                }
            }

            $branchCode = DB::table('branches')->where('id', $branchId)->value('code') ?? 'BR';
            $poNumber = 'PO-' . $branchCode . '-' . date('YmdHis');

            $globalSubtotal = 0;
            $globalTax = 0;
            $globalGrandTotal = 0;

            $purchaseId = DB::table('purchases')->insertGetId([
                'branch_id'      => $branchId,
                'supplier_id'    => $request->supplier_id,
                'user_id'        => $user->id,
                'po_number'      => $poNumber,
                'po_date'        => $request->po_date,
                'purchase_date'  => $request->po_date,
                'status'         => 'draft_po',
                'receipt_status' => 'none',
                'tax_type'       => $request->tax_type,
                'payment_method' => $request->payment_method,
                'term_days'      => $request->term_days ?? 0,
                'dp_amount'      => $dpAmount,
                'dp_account_id'  => $request->dp_account_id,
                'paid_amount'    => $dpAmount,
                'subtotal'       => 0, 
                'tax_amount'     => 0,
                'grand_total'    => 0,
                'notes'          => $request->notes,
                'is_initial_debt'=> false, 
                'created_at'     => Carbon::now(),
                'updated_at'     => Carbon::now(),
            ]);

            foreach ($request->items as $item) {
                $qty = (float) $item['quantity'];
                $price = (float) $item['unit_price'];
                $isBonus = filter_var($item['is_bonus'] ?? false, FILTER_VALIDATE_BOOLEAN);

                if ($isBonus || $price == 0) {
                    $price = 0;
                    $isBonus = true;
                }

                $discountString = $item['discount_string'] ?? '';
                $discountAmount = $this->calculateTieredDiscount($price, $discountString);
                
                $netPrice = $price - $discountAmount;
                $rowTotalPrice = $netPrice * $qty;

                $dpp = 0; 
                $tax = 0;
                
                if (!$isBonus) {
                    if ($request->tax_type === 'include') {
                        $dpp = $rowTotalPrice / 1.11; 
                        $tax = $rowTotalPrice - $dpp;
                    } elseif ($request->tax_type === 'exclude') {
                        $dpp = $rowTotalPrice;
                        $tax = $dpp * 0.11;
                        $rowTotalPrice = $dpp + $tax; 
                    } else {
                        $dpp = $rowTotalPrice;
                        $tax = 0;
                    }
                }

                $globalSubtotal += ($netPrice * $qty); 
                $globalTax += $tax;
                $globalGrandTotal += $rowTotalPrice;
                
                $conversion = (float) ($item['conversion_value'] ?? 1);

                DB::table('purchase_items')->insert([
                    'purchase_id'      => $purchaseId,
                    'product_id'       => $item['product_id'],
                    'quantity'         => $qty,
                    'qty_received'     => 0, 
                    'unit'             => $item['unit'],
                    'conversion_value' => $conversion,
                    'unit_price'       => $price,
                    'discount_string'  => $discountString,
                    'discount_amount'  => $discountAmount * $qty,
                    'total_price'      => $rowTotalPrice,
                    'dpp_amount'       => $dpp,
                    'tax_amount'       => $tax,
                    'is_bonus'         => $isBonus,
                    'created_at'       => Carbon::now(),
                    'updated_at'       => Carbon::now(),
                ]);
            }

            DB::table('purchases')->where('id', $purchaseId)->update([
                'subtotal'    => $globalSubtotal,
                'tax_amount'  => $globalTax,
                'grand_total' => $globalGrandTotal,
            ]);

            // ====================================================================
            // JURNAL UANG MUKA MENGGUNAKAN ACCOUNTING SERVICE (STRICT GL)
            // ====================================================================
            if ($dpAmount > 0) {
                $paymentId = DB::table('debt_payments')->insertGetId([
                    'purchase_id'    => $purchaseId,
                    'branch_id'      => $branchId,
                    'user_id'        => $user->id,
                    'amount'         => $dpAmount,
                    'account_id'     => $request->dp_account_id,
                    'payment_method' => 'cash',
                    'payment_type'   => 'cash',
                    'payment_date'   => $request->po_date,
                    'note'           => 'DP PO: ' . $poNumber,
                    'created_at'     => Carbon::now(),
                    'updated_at'     => Carbon::now()
                ]);

                // WAJIB TERDAFTAR DI ACCOUNTING SETTINGS
                $dpAccId = AccountingService::getAccountId('dp_purchase_account');

                if (!$dpAccId) {
                    throw new \Exception("Sistem Gagal: Akun 'Uang Muka Pembelian' belum dikonfigurasi di Master Akun Global.");
                }

                AccountingService::log([
                    'branch_id'   => $branchId,
                    'entry_date'  => $request->po_date,
                    'description' => 'Uang Muka Pembelian (DP): ' . $poNumber,
                    'reference'   => 'DP-PO-' . $paymentId,
                    'source_type' => 'PURCHASE_DP',
                    'user_id'     => $user->id,
                    'items'       => [
                        ['account_id' => $dpAccId, 'debit' => $dpAmount, 'credit' => 0],
                        ['account_id' => $request->dp_account_id, 'debit' => 0, 'credit' => $dpAmount]
                    ]
                ]);
            }
            // ====================================================================

            DB::commit();
            return response()->json([
                'success'   => true, 
                'message'   => 'PO Berhasil Dibuat', 
                'po_number' => $poNumber
            ]);
            
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]);
        }
    }

    /**
     * ========================================================================
     * 3. UPDATE PO (EDIT)
     * ========================================================================
     */
    public function updatePo(Request $request, $id)
    {
        $request->validate([
            'supplier_id'    => 'required|integer',
            'po_date'        => 'required|date',
            'tax_type'       => 'required|in:non,include,exclude',
            'payment_method' => 'required|in:cash,credit',
            'items'          => 'required|array|min:1'
        ]);

        $user = $request->user();

        DB::beginTransaction();
        try {
            $purchase = DB::table('purchases')->where('id', $id)->first();
            
            if (!$purchase || $purchase->status !== 'draft_po') {
                throw new \Exception("PO tidak ditemukan atau sudah diproses.");
            }

            // PERBAIKAN ENTERPRISE: Keamanan Silang Cabang
            if ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id) {
                throw new \Exception("Akses ditolak: Dokumen PO ini bukan wewenang cabang Anda.");
            }
            
            $receiptCount = DB::table('purchase_receipts')->where('purchase_id', $id)->count();
            if ($receiptCount > 0) {
                throw new \Exception("PO ini sudah ada riwayat penerimaan barang fisik. Batalkan Tanda Terima dahulu.");
            }

            $globalSubtotal = 0; 
            $globalTax = 0; 
            $globalGrandTotal = 0;
            
            DB::table('purchase_items')->where('purchase_id', $id)->delete();

            foreach ($request->items as $item) {
                $qty = (float) $item['quantity']; 
                $price = (float) $item['unit_price'];
                $isBonus = filter_var($item['is_bonus'] ?? false, FILTER_VALIDATE_BOOLEAN);
                
                if ($isBonus || $price == 0) { 
                    $price = 0; 
                    $isBonus = true; 
                }
                
                $discountAmount = $this->calculateTieredDiscount($price, $item['discount_string'] ?? '');
                $netPrice = $price - $discountAmount; 
                $rowTotalPrice = $netPrice * $qty;
                
                $dpp = 0; 
                $tax = 0;
                
                if (!$isBonus) {
                    if ($request->tax_type === 'include') { 
                        $dpp = $rowTotalPrice / 1.11; 
                        $tax = $rowTotalPrice - $dpp; 
                    } elseif ($request->tax_type === 'exclude') { 
                        $dpp = $rowTotalPrice; 
                        $tax = $dpp * 0.11; 
                        $rowTotalPrice = $dpp + $tax; 
                    } else { 
                        $dpp = $rowTotalPrice; 
                        $tax = 0; 
                    }
                }
                
                $globalSubtotal += ($netPrice * $qty); 
                $globalTax += $tax; 
                $globalGrandTotal += $rowTotalPrice;
                
                $conversion = (float) ($item['conversion_value'] ?? 1);

                DB::table('purchase_items')->insert([
                    'purchase_id'      => $id, 
                    'product_id'       => $item['product_id'], 
                    'quantity'         => $qty, 
                    'qty_received'     => 0, 
                    'unit'             => $item['unit'], 
                    'conversion_value' => $conversion, 
                    'unit_price'       => $price, 
                    'discount_string'  => $item['discount_string'] ?? '', 
                    'discount_amount'  => $discountAmount * $qty, 
                    'total_price'      => $rowTotalPrice, 
                    'dpp_amount'       => $dpp, 
                    'tax_amount'       => $tax, 
                    'is_bonus'         => $isBonus, 
                    'created_at'       => Carbon::now(), 
                    'updated_at'       => Carbon::now()
                ]);
            }

            DB::table('purchases')->where('id', $id)->update([
                'supplier_id'    => $request->supplier_id, 
                'po_date'        => $request->po_date, 
                'tax_type'       => $request->tax_type, 
                'payment_method' => $request->payment_method, 
                'term_days'      => $request->term_days ?? 0, 
                'subtotal'       => $globalSubtotal, 
                'tax_amount'     => $globalTax, 
                'grand_total'    => $globalGrandTotal, 
                'receipt_status' => 'none',
                'status'         => 'draft_po',
                'notes'          => $request->notes, 
                'updated_at'     => Carbon::now()
            ]);
            
            DB::commit();
            return response()->json([
                'success' => true, 
                'message' => 'PO Berhasil Diperbarui'
            ]);
            
        } catch (\Exception $e) { 
            DB::rollBack(); 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 4. HAPUS PO
     * ========================================================================
     */
    public function destroyPo(Request $request, $id)
    {
        $user = $request->user();

        DB::beginTransaction();
        try {
            $purchase = DB::table('purchases')->where('id', $id)->first();
            
            if (!$purchase) {
                throw new \Exception("Data tidak ditemukan");
            }

            // PERBAIKAN ENTERPRISE: Keamanan Silang Cabang
            if ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id) {
                throw new \Exception("Akses ditolak: Dokumen PO ini bukan wewenang cabang Anda.");
            }
            
            if ($purchase->status !== 'draft_po') {
                throw new \Exception("Hanya PO status Draft yang boleh dihapus");
            }
            
            $receiptCount = DB::table('purchase_receipts')->where('purchase_id', $id)->count();
            if ($receiptCount > 0) {
                throw new \Exception("PO ini sudah ada riwayat penerimaan barang fisik. Hapus SJ terlebih dahulu.");
            }

            if ($purchase->dp_amount > 0) {
                $payment = DB::table('debt_payments')->where('purchase_id', $id)->first();
                if ($payment) {
                    $journal = DB::table('journal_entries')
                        ->where('reference', 'DP-PO-' . $payment->id)
                        ->first();
                    
                    if ($journal) {
                        DB::table('journal_items')->where('journal_entry_id', $journal->id)->delete();
                        DB::table('journal_entries')->where('id', $journal->id)->delete();
                    }
                    
                    DB::table('debt_payments')->where('id', $payment->id)->delete();
                }
            }
            
            DB::table('purchase_items')->where('purchase_id', $id)->delete();
            DB::table('purchases')->where('id', $id)->delete();
            
            DB::commit();
            return response()->json([
                'success' => true, 
                'message' => 'Data PO & Uang Muka (Jika Ada) berhasil dihapus dan dikembalikan.'
            ]);
            
        } catch (\Exception $e) { 
            DB::rollBack(); 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 5. GET OUTSTANDING ITEMS
     * ========================================================================
     */
    public function getOutstandingItems(Request $request, $id)
    {
        $user = $request->user();
        $purchase = DB::table('purchases')->where('id', $id)->first();
        
        if (!$purchase || ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id)) {
            return response()->json([
                'success' => false, 
                'message' => 'PO tidak ditemukan atau Anda tidak memiliki akses.'
            ]);
        }
        
        $items = DB::table('purchase_items')
            ->join('products', 'purchase_items.product_id', '=', 'products.id')
            ->where('purchase_items.purchase_id', $id)
            ->whereRaw('purchase_items.quantity > purchase_items.qty_received')
            ->select(
                'purchase_items.*', 
                'products.name as product_name', 
                'products.variant_name', 
                'products.sku as product_code'
            )
            ->get();
            
        return response()->json([
            'success'  => true, 
            'data'     => $items, 
            'purchase' => $purchase
        ]);
    }

    /**
     * ========================================================================
     * 6. PENERIMAAN BARANG (PARTIAL RECEIPT & MULTI SJ) + KALKULASI MOVING AVERAGE
     * ========================================================================
     */
    public function receiveGoods(Request $request, $id)
    {
        $request->validate([
            'receipt_date'             => 'required|date', 
            'supplier_delivery_number' => 'required|string', 
            'items'                    => 'required|array|min:1'
        ]);

        $user = $request->user();
        
        DB::beginTransaction();
        try {
            $purchase = DB::table('purchases')->where('id', $id)->first();
            if (!$purchase) {
                throw new \Exception('Data PO tidak ditemukan.');
            }

            // PERBAIKAN ENTERPRISE: Amankan Penerimaan Barang
            if ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: PO ini bukan ditujukan untuk cabang Anda.');
            }
            
            $receiptNumber = 'SJ-' . date('Ymd') . '-' . strtoupper(bin2hex(random_bytes(2)));
            
            $receiptId = DB::table('purchase_receipts')->insertGetId([
                'purchase_id'              => $id, 
                'branch_id'                => $purchase->branch_id, 
                'user_id'                  => $user->id, 
                'receipt_number'           => $receiptNumber, 
                'supplier_delivery_number' => $request->supplier_delivery_number, 
                'receipt_date'             => $request->receipt_date, 
                'notes'                    => $request->notes ?? '', 
                'created_at'               => Carbon::now(), 
                'updated_at'               => Carbon::now()
            ]);
            
            foreach ($request->items as $item) {
                $qtyNow = (float) $item['qty_to_receive'];
                if ($qtyNow <= 0) continue;

                $isBonus = filter_var($item['is_bonus'] ?? false, FILTER_VALIDATE_BOOLEAN);
                $purchaseItemId = $item['purchase_item_id'] ?? null;

                $poItem = DB::table('purchase_items')
                    ->where('purchase_id', $id)
                    ->where('product_id', $item['product_id'])
                    ->when($purchaseItemId, function($q) use ($purchaseItemId) {
                        return $q->where('id', $purchaseItemId);
                    }, function($q) use ($isBonus) {
                        return $q->where('is_bonus', $isBonus);
                    })
                    ->first();

                if (!$poItem) continue;
                
                DB::table('purchase_receipt_items')->insert([
                    'purchase_receipt_id' => $receiptId, 
                    'purchase_item_id'    => $poItem->id, 
                    'product_id'          => $item['product_id'], 
                    'is_bonus'            => $isBonus,
                    'qty_received'        => $qtyNow, 
                    'unit'                => $item['unit'], 
                    'conversion_value'    => $item['conversion_value'] ?? 1, 
                    'created_at'          => Carbon::now(), 
                    'updated_at'          => Carbon::now()
                ]);
                
                DB::table('purchase_items')
                    ->where('id', $poItem->id)
                    ->increment('qty_received', $qtyNow);
                    
                $actualQty = $qtyNow * (float) ($item['conversion_value'] ?? 1);

                // ====================================================================
                // KALKULASI HPP RATA-RATA (MOVING AVERAGE) VIA ACCOUNTING SERVICE
                // ====================================================================
                if (!$isBonus) {
                    $discountPerUnit = $poItem->discount_amount / ($poItem->quantity ?: 1);
                    $netPricePerUnit = $poItem->unit_price - $discountPerUnit;
                    $baseHpp = $netPricePerUnit / (float) ($item['conversion_value'] ?? 1);

                    AccountingService::updateMovingAverage($item['product_id'], $actualQty, $baseHpp);
                }
                // ====================================================================
                
                $stock = DB::table('product_stocks')
                    ->where('product_id', $item['product_id'])
                    ->where('branch_id', $purchase->branch_id)
                    ->first();
                    
                if ($stock) { 
                    DB::table('product_stocks')->where('id', $stock->id)->increment('quantity', $actualQty); 
                } else { 
                    DB::table('product_stocks')->insert([
                        'product_id' => $item['product_id'], 
                        'branch_id'  => $purchase->branch_id, 
                        'quantity'   => $actualQty, 
                        'created_at' => Carbon::now(), 
                        'updated_at' => Carbon::now()
                    ]); 
                }
                
                DB::table('stock_transactions')->insert([
                    'branch_id'       => $purchase->branch_id, 
                    'product_id'      => $item['product_id'], 
                    'type'            => 'purchase_receipt', 
                    'input_quantity'  => $qtyNow, 
                    'input_unit'      => $item['unit'], 
                    'actual_quantity' => $actualQty, 
                    'note'            => 'Terima PO: ' . $purchase->po_number . ' (SJ: ' . $request->supplier_delivery_number . ')' . ($isBonus ? ' [BONUS]' : ''), 
                    'user_id'         => $user->id, 
                    'created_at'      => Carbon::now(), 
                    'updated_at'      => Carbon::now()
                ]);
            }
            
            $allReceived = true; 
            $items = DB::table('purchase_items')->where('purchase_id', $id)->get();
            
            foreach ($items as $it) { 
                if ($it->qty_received < $it->quantity) { 
                    $allReceived = false; 
                    break; 
                } 
            }
            
            DB::table('purchases')->where('id', $id)->update([
                'receipt_status' => $allReceived ? 'completed' : 'partial', 
                'status'         => $allReceived ? 'received' : 'draft_po', 
                'updated_at'     => Carbon::now()
            ]);
            
            DB::commit(); 
            return response()->json([
                'success' => true, 
                'message' => 'Penerimaan barang berhasil diproses dan Nilai HPP Rata-Rata (Moving Average) telah diperbarui.'
            ]);
            
        } catch (\Exception $e) { 
            DB::rollBack(); 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 7. GET RIWAYAT TANDA TERIMA
     * ========================================================================
     */
    public function getReceiptHistory(Request $request)
    {
        $user = $request->user();

        $query = DB::table('purchase_receipts')
            ->join('purchases', 'purchase_receipts.purchase_id', '=', 'purchases.id')
            ->join('suppliers', 'purchases.supplier_id', '=', 'suppliers.id')
            ->join('users', 'purchase_receipts.user_id', '=', 'users.id')
            ->select(
                'purchase_receipts.*', 
                'purchases.po_number', 
                'suppliers.name as supplier_name', 
                'users.name as admin_name'
            )
            ->orderBy('purchase_receipts.created_at', 'desc');

        // PERBAIKAN ENTERPRISE: Isolasi Riwayat SJ
        if ($user && $user->role !== 'owner') {
            $query->where('purchase_receipts.branch_id', $user->branch_id);
        }

        $receipts = $query->get();
            
        if ($receipts->isNotEmpty()) {
            $receiptIds = $receipts->pluck('id')->toArray(); 
            $purchaseIds = $receipts->pluck('purchase_id')->unique()->toArray();
            
            $items = DB::table('purchase_receipt_items')
                ->join('products', 'purchase_receipt_items.product_id', '=', 'products.id')
                ->whereIn('purchase_receipt_items.purchase_receipt_id', $receiptIds)
                ->select(
                    'purchase_receipt_items.*', 
                    'products.name as product_name', 
                    'products.variant_name', 
                    'products.sku as product_code'
                )
                ->get();
                
            $poItems = DB::table('purchase_items')
                ->join('products', 'purchase_items.product_id', '=', 'products.id')
                ->whereIn('purchase_items.purchase_id', $purchaseIds)
                ->select(
                    'purchase_items.*', 
                    'products.name as product_name', 
                    'products.variant_name', 
                    'products.sku as product_code'
                )
                ->get();
                
            foreach ($receipts as $receipt) { 
                $receipt->items = $items->where('purchase_receipt_id', $receipt->id)->values()->toArray(); 
                $receipt->po_items = $poItems->where('purchase_id', $receipt->purchase_id)->values()->toArray(); 
            }
        }
        
        return response()->json([
            'success' => true, 
            'data'    => $receipts
        ]);
    }

    /**
     * ========================================================================
     * 8. VOID (PEMBATALAN) TANDA TERIMA
     * ========================================================================
     */
    public function voidReceipt(Request $request, $id)
    {
        $user = $request->user();

        DB::beginTransaction();
        try {
            $receipt = DB::table('purchase_receipts')->where('id', $id)->first();
            if (!$receipt) {
                throw new \Exception('Data Tanda Terima tidak ditemukan.');
            }

            // PERBAIKAN ENTERPRISE: Proteksi Void Silang Cabang
            if ($user && $user->role !== 'owner' && $receipt->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: Anda tidak memiliki wewenang untuk membatalkan penerimaan cabang lain.');
            }
            
            $purchase = DB::table('purchases')->where('id', $receipt->purchase_id)->first();
            if ($purchase->status === 'invoiced') {
                throw new \Exception('Gagal: PO sudah menjadi Faktur. Batalkan Faktur dahulu.');
            }
            
            $receiptItems = DB::table('purchase_receipt_items')->where('purchase_receipt_id', $id)->get();
            
            foreach ($receiptItems as $item) {
                $actualQtyToRollback = $item->qty_received * $item->conversion_value;
                
                $stock = DB::table('product_stocks')
                    ->where('product_id', $item->product_id)
                    ->where('branch_id', $receipt->branch_id)
                    ->first();
                    
                if ($stock) {
                    DB::table('product_stocks')->where('id', $stock->id)->decrement('quantity', $actualQtyToRollback);
                }
                
                if ($item->purchase_item_id) {
                    DB::table('purchase_items')
                        ->where('id', $item->purchase_item_id)
                        ->decrement('qty_received', $item->qty_received);
                } else {
                    DB::table('purchase_items')
                        ->where('purchase_id', $receipt->purchase_id)
                        ->where('product_id', $item->product_id)
                        ->where('is_bonus', $item->is_bonus ?? false)
                        ->decrement('qty_received', $item->qty_received);
                }
                    
                DB::table('stock_transactions')->insert([
                    'branch_id'       => $receipt->branch_id, 
                    'product_id'      => $item->product_id, 
                    'type'            => 'receipt_void', 
                    'input_quantity'  => -$item->qty_received, 
                    'input_unit'      => $item->unit, 
                    'actual_quantity' => -$actualQtyToRollback, 
                    'note'            => 'BATAL Tanda Terima: ' . $receipt->receipt_number, 
                    'user_id'         => $user->id, 
                    'created_at'      => Carbon::now(), 
                    'updated_at'      => Carbon::now()
                ]);
            }
            
            $allZero = true; 
            $allComplete = true; 
            $poItems = DB::table('purchase_items')->where('purchase_id', $receipt->purchase_id)->get();
            
            foreach($poItems as $poi) { 
                if ($poi->qty_received > 0) $allZero = false; 
                if ($poi->qty_received < $poi->quantity) $allComplete = false; 
            }
            
            $newReceiptStatus = 'none'; 
            $newStatus = 'draft_po';
            
            if (!$allZero && !$allComplete) {
                $newReceiptStatus = 'partial';
            } elseif ($allComplete) { 
                $newReceiptStatus = 'completed'; 
                $newStatus = 'received'; 
            }
            
            DB::table('purchases')->where('id', $receipt->purchase_id)->update([
                'receipt_status' => $newReceiptStatus, 
                'status'         => $newStatus, 
                'updated_at'     => Carbon::now()
            ]);
            
            DB::table('purchase_receipt_items')->where('purchase_receipt_id', $id)->delete();
            DB::table('purchase_receipts')->where('id', $id)->delete();
            
            DB::commit(); 
            return response()->json([
                'success' => true, 
                'message' => 'Tanda Terima berhasil DIBATALKAN.'
            ]);
            
        } catch (\Exception $e) { 
            DB::rollBack(); 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 9. CLOSE PO
     * ========================================================================
     */
    public function closePo(Request $request, $id)
    {
        $user = $request->user();

        try {
            $purchase = DB::table('purchases')->where('id', $id)->first();
            
            if (!$purchase) {
                throw new \Exception('Data PO tidak ditemukan.');
            }

            // PERBAIKAN ENTERPRISE: Keamanan Eksekusi
            if ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: Anda tidak memiliki wewenang untuk menutup PO cabang lain.');
            }

            DB::table('purchases')->where('id', $id)->update([
                'status'         => 'received', 
                'receipt_status' => 'completed', 
                'notes'          => DB::raw("CONCAT(notes, ' - PO CLOSED MANUALLY')"), 
                'updated_at'     => Carbon::now()
            ]);
            
            return response()->json([
                'success' => true, 
                'message' => 'PO telah ditutup secara manual.'
            ]);
            
        } catch (\Exception $e) { 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 10. VALIDASI FAKTUR -> LANDED COST ALLOCATION + PENJURNALAN OTOMATIS
     * ========================================================================
     */
    public function createInvoice(Request $request, $id)
    {
        $request->validate([
            'invoice_number' => 'required|string', 
            'invoice_date'   => 'required|date', 
            'term_days'      => 'required|integer', 
            'other_costs'    => 'numeric|min:0'
        ]);

        $user = $request->user();
        
        DB::beginTransaction();
        try {
            $purchase = DB::table('purchases')->where('id', $id)->first();
            if (!$purchase || $purchase->status !== 'received') {
                throw new \Exception('Barang belum diterima penuh/diclose, atau faktur sudah dibuat.');
            }

            // PERBAIKAN ENTERPRISE: Proteksi API Tampering saat Validasi
            if ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: Anda tidak berhak memvalidasi Faktur cabang ini.');
            }

            $items = DB::table('purchase_items')->where('purchase_id', $id)->get();
            $actualSubtotal = 0;
            
            foreach ($items as $item) {
                $qtyReceived = (float) $item->qty_received; 
                $price = $item->is_bonus ? 0 : (float) $item->unit_price;
                $discountAmount = $this->calculateTieredDiscount($price, $item->discount_string);
                $actualSubtotal += ($price - $discountAmount) * $qtyReceived;
            }

            $actualTax = 0; 
            $actualGrandTotal = 0; 
            $otherCosts = (float) ($request->other_costs ?? 0); 
            
            if ($purchase->tax_type === 'include') { 
                $dpp = $actualSubtotal / 1.11; 
                $actualTax = $actualSubtotal - $dpp; 
                $actualGrandTotal = $actualSubtotal + $otherCosts; 
            } elseif ($purchase->tax_type === 'exclude') { 
                $actualTax = $actualSubtotal * 0.11; 
                $actualGrandTotal = $actualSubtotal + $actualTax + $otherCosts; 
            } else { 
                $actualGrandTotal = $actualSubtotal + $otherCosts; 
            }

            // =============================================================
            // ENTERPRISE LOGIC: LANDED COST ALLOCATION & UPDATE HPP L1
            // =============================================================
            foreach ($items as $item) {
                $qtyReceived = (float) $item->qty_received; 
                if ($qtyReceived <= 0 || $item->is_bonus) continue;

                $price = (float) $item->unit_price;
                $discountAmount = $this->calculateTieredDiscount($price, $item->discount_string);
                $netPrice = $price - $discountAmount;
                $itemSubtotal = $netPrice * $qtyReceived;

                $allocatedCost = 0;
                if ($actualSubtotal > 0 && $otherCosts > 0) {
                    $allocatedCost = ($itemSubtotal / $actualSubtotal) * $otherCosts;
                }

                $hppPerUnit = $netPrice + ($allocatedCost / $qtyReceived);
                $conversion = (float) ($item->conversion_value ?? 1);
                $baseHpp = $hppPerUnit / $conversion;

                // Eksekusi Update harga beli master untuk acuan masa depan
                DB::table('products')->where('id', $item->product_id)->update([
                    'buy_price'  => $baseHpp,
                    'updated_at' => Carbon::now()
                ]);
            }
            // =============================================================

            $remainingPayable = $actualGrandTotal - (float) $purchase->dp_amount;
            $dueDate = Carbon::parse($request->invoice_date)->addDays($request->term_days);
            
            DB::table('purchases')->where('id', $id)->update([
                'subtotal'       => $actualSubtotal, 
                'tax_amount'     => $actualTax, 
                'other_costs'    => $otherCosts, 
                'grand_total'    => $actualGrandTotal, 
                'status'         => 'invoiced', 
                'invoice_number' => $request->invoice_number, 
                'purchase_date'  => $request->invoice_date, 
                'term_days'      => $request->term_days, 
                'due_date'       => $dueDate, 
                'payment_status' => ($remainingPayable <= 0 ? 'paid' : 'pending'), 
                'updated_at'     => Carbon::now()
            ]);

            // =============================================================
            // JURNALISASI FAKTUR PEMBELIAN MENGGUNAKAN ACCOUNTING SERVICE
            // =============================================================
            
            $inventoryAcc = AccountingService::getAccountId('persediaan_barang');
            $payableAcc = AccountingService::getAccountId('hutang_usaha');
            $dpAccId = AccountingService::getAccountId('dp_purchase_account');

            if (!$inventoryAcc || !$payableAcc) {
                throw new \Exception("Sistem Gagal: Akun Persediaan atau Hutang Usaha belum dikonfigurasi di Master Akun.");
            }

            $journalItems = [];
            // 1. Debit Persediaan (Total HPP)
            $journalItems[] = ['account_id' => $inventoryAcc, 'debit' => $actualGrandTotal, 'credit' => 0];

            // 2. Kredit Uang Muka (Jika ada DP)
            if ($purchase->dp_amount > 0) {
                if (!$dpAccId) throw new \Exception("Sistem Gagal: Akun Uang Muka Pembelian belum dikonfigurasi.");
                $journalItems[] = ['account_id' => $dpAccId, 'debit' => 0, 'credit' => $purchase->dp_amount];
            }

            // 3. Kredit Hutang Usaha (Sisa yang harus dibayar)
            if ($remainingPayable > 0) {
                $journalItems[] = ['account_id' => $payableAcc, 'debit' => 0, 'credit' => $remainingPayable];
            }

            AccountingService::log([
                'branch_id'   => $purchase->branch_id,
                'entry_date'  => $request->invoice_date,
                'description' => 'Faktur Pembelian: ' . $request->invoice_number,
                'reference'   => $request->invoice_number,
                'source_type' => 'PURCHASE_INVOICE',
                'user_id'     => $user->id,
                'items'       => $journalItems
            ]);
            // =============================================================

            DB::commit(); 
            return response()->json([
                'success' => true, 
                'message' => 'Faktur divalidasi dan dijurnal ke Buku Besar. Biaya Ongkir telah dialokasikan.'
            ]);
            
        } catch (\Exception $e) { 
            DB::rollBack(); 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 12. PEMBATALAN FAKTUR (VOID INVOICE)
     * ========================================================================
     */
    public function voidInvoice(Request $request, $id)
    {
        $user = $request->user();

        DB::beginTransaction();
        try {
            $purchase = DB::table('purchases')->where('id', $id)->first();
            
            if (!$purchase || $purchase->status !== 'invoiced') {
                throw new \Exception('Data Faktur tidak valid.');
            }

            // PERBAIKAN ENTERPRISE: Keamanan Eksekusi Void
            if ($user && $user->role !== 'owner' && $purchase->branch_id !== $user->branch_id) {
                throw new \Exception('Akses ditolak: Dokumen ini bukan wewenang cabang Anda.');
            }
            
            if ((float)$purchase->paid_amount > (float)$purchase->dp_amount) {
                throw new \Exception('Faktur sudah ada pembayaran cicilan. Batalkan pembayaran cicilan terlebih dahulu.');
            }

            // =============================================================
            // HAPUS JURNAL DARI BUKU BESAR
            // =============================================================
            $journal = DB::table('journal_entries')
                ->where('reference', $purchase->invoice_number)
                ->where('source_type', 'PURCHASE_INVOICE')
                ->first();
                
            if ($journal) { 
                DB::table('journal_items')->where('journal_entry_id', $journal->id)->delete(); 
                DB::table('journal_entries')->where('id', $journal->id)->delete(); 
            }
            // =============================================================

            DB::table('purchases')->where('id', $id)->update([
                'status'         => 'received', 
                'invoice_number' => null, 
                'term_days'      => 0, 
                'due_date'       => null, 
                'other_costs'    => 0, 
                'payment_status' => 'pending', 
                'updated_at'     => Carbon::now()
            ]);
            
            DB::commit(); 
            return response()->json([
                'success' => true, 
                'message' => 'Faktur dan Jurnal Akuntansi berhasil dibatalkan.'
            ]);
            
        } catch (\Exception $e) { 
            DB::rollBack(); 
            return response()->json([
                'success' => false, 
                'message' => $e->getMessage()
            ]); 
        }
    }

    /**
     * ========================================================================
     * 13. HELPER: MENGHITUNG DISKON (SMART DETECTION: DEFAULT RUPIAH)
     * ========================================================================
     */
    private function calculateTieredDiscount($basePrice, $discountString)
    {
        if (empty($discountString)) return 0;
        
        $tiers = explode('+', strtolower(str_replace(' ', '', $discountString)));
        $currentPrice = $basePrice;
        
        foreach ($tiers as $tier) {
            if (str_contains($tier, '%')) {
                $percentage = (float) str_replace('%', '', $tier);
                if ($percentage > 0 && $percentage <= 100) {
                    $currentPrice -= ($currentPrice * ($percentage / 100));
                }
            } 
            else {
                $nominal = (float) str_replace(['rp', '.'], '', $tier);
                if ($nominal > 0) {
                    $currentPrice -= $nominal;
                }
            }
        }
        
        if ($currentPrice < 0) {
            $currentPrice = 0;
        }
        
        return $basePrice - $currentPrice;
    }

    /**
     * ========================================================================
     * 14. GET AKUN KAS/BANK SESUAI CABANG (ISOLASI)
     * ========================================================================
     */
    public function getBranchAccounts(Request $request)
    {
        try {
            $user = $request->user();
            $requestedBranch = $request->query('branch_id');

            // PERBAIKAN ENTERPRISE: Isolasi Mutlak Data Cabang (Anti IDOR)
            $branchId = ($user && $user->role === 'owner') ? $requestedBranch : $user->branch_id;

            if (!$branchId) {
                return response()->json(['success' => true, 'data' => []]);
            }

            $accounts = DB::table('branch_accounts')
                ->join('accounts', 'branch_accounts.account_id', '=', 'accounts.id')
                ->where('branch_accounts.branch_id', $branchId)
                ->where('branch_accounts.is_active', 1)
                ->select('accounts.id', 'accounts.name', 'accounts.code')
                ->get();

            return response()->json([
                'success' => true, 
                'data' => $accounts
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false, 
                'message' => 'Gagal memuat akun cabang: ' . $e->getMessage()
            ], 500);
        }
    }
}