<?php

namespace App\Http\Controllers\Api;

use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\Sale;
use App\Models\ProductStock; 
use Carbon\Carbon;
use App\Services\AccountingService;

class PosOnlineOrderController extends Controller
{
    /**
     * 1. MENARIK DAFTAR ANTRIAN PESANAN (Membaca dari Sales Orders)
     * Digunakan oleh Admin Gudang Online untuk melihat pesanan masuk
     */
    public function getPendingOrders(Request $request)
    {
        $request->validate([
            'branch_id' => 'required|exists:branches,id'
        ]);

        $user = $request->user();

        // PERBAIKAN ENTERPRISE: Amankan Tarikan Data Antrean
        // Cegah Admin Cabang merequest antrean cabang lain dengan mengubah parameter branch_id
        $branchId = ($user && $user->role !== 'owner') ? $user->branch_id : $request->branch_id;

        // MENGAMBIL DARI TABEL SALES ORDERS (Pesanan yg belum naik mobil)
        $rawOrders = DB::table('sales_orders')
            ->where('fulfillment_branch_id', $branchId)
            ->whereIn('status', ['pending', 'reschedule'])
            ->orderBy('created_at', 'asc')
            ->get();

        $orders = [];
        foreach ($rawOrders as $order) {
            $items = DB::table('sales_order_items')
                ->join('products', 'sales_order_items.product_id', '=', 'products.id')
                ->where('sales_order_id', $order->id)
                ->select('sales_order_items.*', 'products.name as product_name')
                ->get();
                
            $orders[] = [
                'id' => $order->id, // ID Pesanan (Sales Order)
                'invoice_number' => $order->so_number,
                'customer_name' => $order->customer_name,
                'shipping_address' => $order->shipping_address,
                'grand_total' => (float) $order->grand_total,
                'status' => $order->status,
                'dp_amount' => (float) ($order->dp_amount ?? 0), // Info DP
                'created_at' => $order->created_at,
                'items' => $items
            ];
        }

        // Tarik data supir 
        $drivers = \App\Models\User::where('role', 'driver')
            ->where('branch_id', $branchId)
            ->select('id', 'name')
            ->get()
            ->map(function($driver) {
                return [
                    'id' => $driver->id,
                    'name' => $driver->name,
                    'vehicle' => 'Armada P-LINK' 
                ];
            });

        return response()->json([
            'status' => 'success',
            'message' => 'Data pesanan online berhasil ditarik',
            'data' => $orders,
            'drivers' => $drivers 
        ], 200);
    }

    /**
     * 2. LOGIKA BARANG NAIK MOBIL (Konversi SO ke Faktur + Jurnal Akuntansi)
     * Titik krusial di mana stok fisik berkurang dan piutang diakui.
     */
    public function processOrder(Request $request)
    {
        // Parameter sale_id dari frontend kini mewakili ID dari sales_orders
        $request->validate([
            'sale_id' => 'required', 
            'driver_id' => 'required|exists:users,id', 
        ]);

        $user = $request->user();
        $userId = $user->id ?? 1;

        try {
            DB::beginTransaction();

            // 1. Validasi Sales Order
            $so = DB::table('sales_orders')->where('id', $request->sale_id)->first();

            if (!$so) {
                throw new \Exception("Data pesanan tidak ditemukan di sistem.");
            }

            // PERBAIKAN ENTERPRISE: Proteksi Eksekusi Lintas Cabang (API Tampering)
            if ($user && $user->role !== 'owner' && $so->fulfillment_branch_id !== $user->branch_id) {
                throw new \Exception("Akses ditolak: Pesanan ini bukan wewenang cabang Anda.");
            }

            if (!in_array($so->status, ['pending', 'reschedule'])) {
                throw new \Exception("Pesanan ini sudah diproses atau dibatalkan.");
            }

            // 2. Buat Faktur Penjualan (Sale) Resmi karena barang keluar gudang
            $invoiceNumber = str_replace('SO-', 'INV-', $so->so_number);

            // Perhitungan Pajak
            $customer = DB::table('customers')->where('id', $so->customer_id)->first();
            $taxSetting = DB::table('settings')->where('key', 'ppn_rate')->first();
            $ppnRate = $taxSetting ? ((float) $taxSetting->value / 100) : 0.11;
            
            $taxAmount = 0;
            $dpp = $so->subtotal;

            if ($customer && $customer->is_pkp == 1) {
                if ($customer->default_tax_method === 'exclude') {
                    $taxAmount = $dpp * $ppnRate;
                } else {
                    $dpp = $so->subtotal / (1 + $ppnRate);
                    $taxAmount = $so->subtotal - $dpp;
                }
            }

            $saleId = DB::table('sales')->insertGetId([
                'branch_id' => $so->fulfillment_branch_id,
                'user_id' => $userId, 
                'customer_id' => $so->customer_id,
                'sales_order_id' => $so->id, // [FIX] Relasi ke Sales Order wajib diisi
                'customer_name' => $so->customer_name,
                'invoice_number' => $invoiceNumber,
                'subtotal' => $so->subtotal,
                'tax_amount' => $taxAmount,
                'discount_amount' => $so->discount_amount,
                'shipping_fee' => $so->shipping_fee,
                'grand_total' => $so->grand_total,
                'payment_method' => $so->payment_method,
                'payment_status' => 'pending', 
                'is_online_order' => 1,
                'delivery_lat' => $so->delivery_lat,
                'delivery_lng' => $so->delivery_lng,
                'shipping_address' => $so->shipping_address,
                'driver_id' => $request->driver_id,
                'delivery_status' => 'dikirim', // Supir akan melihat status ini (SINKRON DENGAN FINANCE)
                'created_at' => now(),
                'updated_at' => now(),
            ]);

            // 3. Pindahkan Barang dan Jalankan Mutasi Stok
            $soItems = DB::table('sales_order_items')->where('sales_order_id', $so->id)->get();
            $totalCogs = 0;

            foreach ($soItems as $item) {
                $product = \App\Models\Product::find($item->product_id);
                $multiplier = 1;
                
                if ($product) {
                    $uName = strtoupper(trim($item->unit_name));
                    if ($uName === strtoupper(trim($product->buy_unit ?? ''))) $multiplier = $product->conversion_factor ?? 1;
                    elseif ($uName === strtoupper(trim($product->unit_3_name ?? ''))) $multiplier = $product->conversion_3_qty ?? 1;
                    elseif ($uName === strtoupper(trim($product->unit_4_name ?? ''))) $multiplier = $product->conversion_4_qty ?? 1;
                    
                    // Gunakan Moving Average Cost, fallback ke buy_price
                    $hppItem = (isset($product->average_cost) && $product->average_cost > 0) ? $product->average_cost : ($product->buy_price ?? 0);
                    $totalCogs += ($hppItem * ($item->qty * $multiplier));
                }

                $totalBaseQty = $item->qty * $multiplier;

                // Insert ke Sale Items
                DB::table('sale_items')->insert([
                    'sale_id' => $saleId,
                    'product_id' => $item->product_id,
                    'product_name' => $product ? $product->name : 'Item Online',
                    'unit' => $item->unit_name,
                    'base_conversion_factor' => $multiplier,
                    'quantity' => $item->qty,
                    'unit_price' => $item->price,
                    'total_price' => $item->total_price,
                    'created_at' => now(),
                    'updated_at' => now()
                ]);

                // *** LOGIKA UTAMA: GUDANG DROPPING ***
                // 1. Kurangi Quantity Fisik (Keluar Pintu Gudang)
                // 2. Kurangi Reserved Qty (Tugas Booking Selesai)
                $stock = \App\Models\ProductStock::where('branch_id', $so->fulfillment_branch_id)
                            ->where('product_id', $item->product_id)
                            ->first();

                if ($stock) {
                    $stock->decrement('quantity', $totalBaseQty);
                    $stock->decrement('reserved_qty', $totalBaseQty);
                    if ($stock->reserved_qty < 0) $stock->reserved_qty = 0; 
                    $stock->save();
                }

                // Catat di Jurnal Mutasi (Barang Keluar)
                \App\Models\StockTransaction::create([
                    'branch_id' => $so->fulfillment_branch_id,
                    'product_id' => $item->product_id,
                    'type' => 'sale', 
                    'input_quantity' => -1 * abs($item->qty), 
                    'input_unit' => $item->unit_name,
                    'actual_quantity' => -1 * abs($totalBaseQty), 
                    'user_id' => $userId,
                    'note' => 'Dropping Pengiriman Nota: ' . $invoiceNumber,
                ]);
            }

            // 4. Update Status Sales Order (Selesai diproses)
            DB::table('sales_orders')->where('id', $so->id)->update([
                'status' => 'dikirim',
                'updated_at' => now()
            ]);

            // =========================================================================
            // 5. POSTING JURNAL OTOMATIS (STRICT VALIDATION GL)
            // =========================================================================
            $accPiutang = AccountingService::getAccountId('piutang_usaha');
            $accPendapatan = AccountingService::getAccountId('pendapatan_penjualan');
            $accPpn = AccountingService::getAccountId('ppn_keluaran');
            $accHpp = AccountingService::getAccountId('hpp');
            $accPersediaan = AccountingService::getAccountId('persediaan_barang');

            if (!$accPiutang || !$accPendapatan || !$accHpp || !$accPersediaan) {
                throw new \Exception("Sistem Gagal: Master Akun Global untuk Penjualan (Piutang/Pendapatan/HPP/Persediaan) belum dikonfigurasi.");
            }

            $journalItems = [];

            // 1. Debit Piutang
            $journalItems[] = ['account_id' => $accPiutang, 'debit' => $so->grand_total, 'credit' => 0];
            
            // 2. Kredit PPN Keluaran
            if ($taxAmount > 0 && $accPpn) {
                $journalItems[] = ['account_id' => $accPpn, 'debit' => 0, 'credit' => $taxAmount];
            }
            
            // 3. Kredit Pendapatan Penjualan (DPP + Ongkir)
            $journalItems[] = ['account_id' => $accPendapatan, 'debit' => 0, 'credit' => $dpp + $so->shipping_fee];
            
            // 4. Debit HPP
            $journalItems[] = ['account_id' => $accHpp, 'debit' => $totalCogs, 'credit' => 0];
            
            // 5. Kredit Persediaan Barang
            $journalItems[] = ['account_id' => $accPersediaan, 'debit' => 0, 'credit' => $totalCogs];

            AccountingService::log([
                'branch_id'   => $so->fulfillment_branch_id,
                'entry_date'  => Carbon::today()->toDateString(),
                'description' => 'Penjualan Online: ' . $invoiceNumber . ' (' . $so->customer_name . ')',
                'reference'   => $invoiceNumber,
                'source_type' => 'sales_invoice',
                'user_id'     => $userId,
                'items'       => $journalItems
            ]);
            // =========================================================================

            DB::commit();

            return response()->json([
                'status' => 'success',
                'message' => 'Barang berhasil dimuat ke armada. Faktur diterbitkan untuk Supir.',
            ], 200);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'status' => 'error',
                'message' => 'Gagal memproses pengiriman: ' . $e->getMessage()
            ], 400);
        }
    }

    /**
     * 3. SUPIR MELIHAT DAFTAR ANTARAN (Membaca dari Faktur/Sales yang Sah)
     */
    public function getDriverDeliveries(Request $request)
    {
        $user = $request->user();

        // Supir membaca dari tabel `sales`
        // PERHATIAN: Logika 'sales.driver_id' = $user->id ini sudah benar untuk mengisolasi data per Supir.
        $deliveries = Sale::with('items.product')
            ->leftJoin('sales_orders', 'sales.sales_order_id', '=', 'sales_orders.id')
            ->where('sales.driver_id', $user->id)
            ->whereIn('sales.delivery_status', ['dikirim', 'selesai'])
            ->select('sales.*', 'sales_orders.dp_amount', 'sales_orders.so_number')
            ->orderBy('sales.created_at', 'desc')
            ->get();

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

    /**
     * 4. SUPIR SELESAIKAN PENGIRIMAN (KONFIRMASI SAMPAI)
     */
    public function completeDelivery(Request $request)
    {
        $request->validate([
            'sale_id' => 'required|exists:sales,id',
            'notes' => 'nullable|string'
        ]);

        $user = $request->user();

        try {
            DB::beginTransaction();

            $sale = Sale::findOrFail($request->sale_id);

            // PERBAIKAN ENTERPRISE: Proteksi API Tampering Supir
            if ($user && $user->role === 'driver' && (int)$sale->driver_id !== (int)$user->id) {
                throw new \Exception("Akses ditolak: Faktur ini bukan tugas pengiriman Anda.");
            }

            // Status harus 'terkirim' atau 'selesai' agar muncul di menu Validasi Finance
            $sale->delivery_status = 'selesai';
            $sale->save();
            DB::table('sales_orders')->where('id', $sale->sales_order_id)->update(['status' => 'selesai', 'updated_at' => now()]);

            // Catat log pengiriman sukses
            DB::table('delivery_logs')->insert([
                'sale_id' => $sale->id,
                'sales_order_id' => $sale->sales_order_id,
                'driver_id' => $user->id,
                'status' => 'terkirim',
                'note' => $request->notes ?? 'Diterima Pelanggan',
                'created_at' => now(),
                'updated_at' => now()
            ]);

            DB::commit();

            return response()->json([
                'status' => 'success',
                'message' => 'Status pengiriman berhasil diperbarui menjadi Terkirim. Menunggu validasi kasir.'
            ]);

        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['status' => 'error', 'message' => $e->getMessage()], 400);
        }
    }

    /**
     * 5. SUPIR LAPOR GAGAL (VOID + JURNAL PEMBALIK)
     */
    public function cancelDelivery(Request $request)
    {
        $request->validate([
            'sale_id' => 'required|exists:sales,id',
            'reason' => 'required|string'
        ]);
        
        $user = $request->user();

        try {
            DB::beginTransaction();
            $sale = DB::table('sales')->where('id', $request->sale_id)->first();
            
            if (!$sale || $sale->delivery_status === 'void') throw new \Exception("Faktur tidak valid.");
            
            // PERBAIKAN ENTERPRISE: Proteksi Lintas Supir
            if ($user && $user->role === 'driver' && (int)$sale->driver_id !== (int)$user->id) {
                throw new \Exception("Akses ditolak: Faktur ini bukan tugas pengiriman Anda.");
            }

            // 1. Balikkan Stok
            $items = DB::table('sale_items')->where('sale_id', $sale->id)->get();
            $totalCogs = 0;
            foreach ($items as $item) {
                $actualQty = $item->quantity * $item->base_conversion_factor;
                $product = DB::table('products')->where('id', $item->product_id)->first();
                
                if ($product) {
                    $hppItem = (isset($product->average_cost) && $product->average_cost > 0) ? $product->average_cost : ($product->buy_price ?? 0);
                    $totalCogs += ($hppItem * $actualQty);
                }

                DB::table('product_stocks')->where('branch_id', $sale->branch_id)->where('product_id', $item->product_id)
                    ->update([
                        'quantity' => DB::raw("quantity + $actualQty"), 
                        'reserved_qty' => DB::raw("reserved_qty + $actualQty")
                    ]);

                // Kurangi qty_delivered di SO Induk
                DB::table('sales_order_items')
                    ->where('sales_order_id', $sale->sales_order_id)
                    ->where('product_id', $item->product_id)
                    ->update(['qty_delivered' => DB::raw("GREATEST(qty_delivered - " . $item->quantity . ", 0)")]);
            }

            // 2. VOID Faktur (Audit Trail Tetap Ada)
            DB::table('sales')->where('id', $sale->id)->update([
                'delivery_status' => 'void', 
                'payment_status' => 'void', 
                'updated_at' => now()
            ]);
            
            // Kembalikan ke antrean reschedule
            DB::table('sales_orders')->where('id', $sale->sales_order_id)->update(['status' => 'reschedule']);

            // =========================================================================
            // 3. JURNAL PEMBALIK (REVERSAL) DENGAN STRICT GL
            // =========================================================================
            $accPiutang = AccountingService::getAccountId('piutang_usaha');
            $accPendapatan = AccountingService::getAccountId('pendapatan_penjualan');
            $accPpn = AccountingService::getAccountId('ppn_keluaran');
            $accHpp = AccountingService::getAccountId('hpp');
            $accPersediaan = AccountingService::getAccountId('persediaan_barang');

            if (!$accPiutang || !$accPendapatan || !$accHpp || !$accPersediaan) {
                throw new \Exception("Sistem Gagal: Master Akun Global untuk Penjualan belum dikonfigurasi.");
            }

            $journalItems = [];

            // 1. Balik Piutang ke Kredit
            $journalItems[] = ['account_id' => $accPiutang, 'debit' => 0, 'credit' => $sale->grand_total];
            
            // 2. Balik PPN Keluaran ke Debit (Jika ada)
            if ($sale->tax_amount > 0 && $accPpn) {
                $journalItems[] = ['account_id' => $accPpn, 'debit' => $sale->tax_amount, 'credit' => 0];
            }

            // 3. Balik Pendapatan Penjualan ke Debit (Grand Total dikurangi PPN)
            $pendapatanYangDibatalkan = $sale->grand_total - $sale->tax_amount;
            $journalItems[] = ['account_id' => $accPendapatan, 'debit' => $pendapatanYangDibatalkan, 'credit' => 0];
            
            // 4. Balik Persediaan Barang ke Debit
            $journalItems[] = ['account_id' => $accPersediaan, 'debit' => $totalCogs, 'credit' => 0];

            // 5. Balik Harga Pokok Penjualan (HPP) ke Kredit
            $journalItems[] = ['account_id' => $accHpp, 'debit' => 0, 'credit' => $totalCogs];

            AccountingService::log([
                'branch_id'   => $sale->branch_id,
                'entry_date'  => Carbon::today()->toDateString(),
                'description' => 'VOID Gagal Kirim: ' . $sale->invoice_number,
                'reference'   => $sale->invoice_number . '-VOID',
                'source_type' => 'sale_void',
                'user_id'     => $user->id,
                'items'       => $journalItems
            ]);
            // =========================================================================
            
            DB::commit();
            return response()->json(['status' => 'success', 'message' => 'Laporan Gagal Kirim diproses (VOID) dan jurnal pembalik berhasil dicatat.']);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json(['status' => 'error', 'message' => $e->getMessage()], 400);
        }
    }
}