<?php

namespace App\Http\Controllers;

use App\Models\{User, Transaction, TransactionItem, Product, CashSession, Discount, StockMovement, Setting, Supplier, Purchase, PurchaseItem, Expense};
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

use Illuminate\Routing\Controllers\HasMiddleware;
use Illuminate\Routing\Controllers\Middleware;

class PosController extends Controller implements HasMiddleware
{
    public static function middleware(): array
    {
        return [
            'auth',
            new Middleware('check.active.session', except: ['openSession', 'storeSession', 'receipt']),
        ];
    }

    /**
     * Halaman utama POS kasir
     */
    public function index()
    {
        $session = auth()->user()->getActiveSession();
        $categories = \App\Models\Category::active()->orderBy('sort_order')->get();
        $products   = Product::active()
            ->with('category')
            ->where('stock', '>', 0)
            ->orWhere('track_stock', false)
            ->orderBy('name')
            ->get();

        $settings = [
            'tax_enabled' => Setting::get('tax_enabled', true),
            'tax_percent' => Setting::get('tax_percent', 11),
            'store_name'  => Setting::get('store_name', config('app.name')),
            'printer_width' => Setting::get('printer_width', '80'),
            'printer_auto_print' => Setting::get('printer_auto_print', true),
            'printer_show_logo' => Setting::get('printer_show_logo', true),
            'printer_type' => Setting::get('printer_type', 'thermal'),
            'printer_font_size' => Setting::get('printer_font_size', 'sm'),
        ];

        return view('pos.index', compact('session', 'categories', 'products', 'settings'));
    }

    /**
     * Cari produk via AJAX (barcode / nama / SKU)
     */
    public function searchProduct(Request $request)
    {
        $term = $request->q;
        $products = Product::active()
            ->search($term)
            ->with('category')
            ->limit(20)
            ->get()
            ->map(fn($p) => [
                'id'            => $p->id,
                'name'          => $p->name,
                'sku'           => $p->sku,
                'barcode'       => $p->barcode,
                'price'         => $p->selling_price,
                'cost'          => $p->cost_price,
                'stock'         => $p->stock,
                'track_stock'   => $p->track_stock,
                'unit'          => $p->unit,
                'category'      => $p->category?->name,
                'image'         => $p->image_url,
                'is_low_stock'  => $p->is_low_stock,
            ]);

        return response()->json($products);
    }

    /**
     * Proses transaksi baru
     */
    public function store(Request $request)
    {
        $request->validate([
            'items'          => 'required|array|min:1',
            'items.*.id'     => 'required|exists:products,id',
            'items.*.qty'    => 'required|integer|min:1',
            'items.*.price'  => 'required|numeric|min:0',
            'payment_method' => 'required|in:cash,transfer,qris,kartu_debit,kartu_kredit,piutang',
            'amount_paid'    => 'required_if:payment_method,cash|numeric|min:0',
        ]);

        try {
            DB::beginTransaction();

            $session = auth()->user()->getActiveSession();
            $items   = collect($request->items);

            // Hitung subtotal
            $subtotal = $items->sum(fn($i) => $i['price'] * $i['qty']);

            // Diskon global
            $discountAmount = 0;
            if ($request->discount_code) {
                $discount = Discount::valid()->where('code', $request->discount_code)->first();
                if ($discount) {
                    $discountAmount = $discount->calculate($subtotal);
                }
            } elseif ($request->discount_amount > 0) {
                $discountAmount = min($request->discount_amount, $subtotal);
            }

            $afterDiscount = $subtotal - $discountAmount;

            // PPN
            $taxPercent = Setting::get('tax_enabled', true) ? Setting::get('tax_percent', 11) : 0;
            $taxAmount  = $afterDiscount * ($taxPercent / 100);
            $grandTotal = $afterDiscount + $taxAmount;

            $amountPaid   = $request->payment_method === 'cash' ? $request->amount_paid : $grandTotal;
            $changeAmount = max(0, $amountPaid - $grandTotal);

            // Buat transaksi
            $transaction = Transaction::create([
                'invoice_number'  => Transaction::generateInvoice(),
                'user_id'         => auth()->id(),
                'cash_session_id' => $session?->id,
                'customer_name'   => $request->customer_name ?? 'Umum',
                'customer_phone'  => $request->customer_phone,
                'subtotal'        => $subtotal,
                'discount_amount' => $discountAmount,
                'tax_percent'     => $taxPercent,
                'tax_amount'      => $taxAmount,
                'grand_total'     => $grandTotal,
                'payment_method'  => $request->payment_method,
                'amount_paid'     => $amountPaid,
                'change_amount'   => $changeAmount,
                'status'          => 'completed',
                'notes'           => $request->notes,
                'transaction_date'=> now(),
            ]);

            // Buat item & update stok
            foreach ($items as $item) {
                $product = Product::findOrFail($item['id']);

                // Validasi stok
                if ($product->track_stock && $product->stock < $item['qty']) {
                    throw new \Exception("Stok {$product->name} tidak mencukupi. Tersisa: {$product->stock}");
                }

                $discountItem = isset($item['discount']) ? $item['discount'] : 0;
                $unitPrice    = $item['price'];
                $itemSubtotal = ($unitPrice - $discountItem) * $item['qty'];

                TransactionItem::create([
                    'transaction_id'  => $transaction->id,
                    'product_id'      => $product->id,
                    'product_name'    => $product->name,
                    'product_sku'     => $product->sku,
                    'cost_price'      => $product->cost_price,
                    'unit_price'      => $unitPrice,
                    'quantity'        => $item['qty'],
                    'unit'            => $product->unit,
                    'discount_amount' => $discountItem * $item['qty'],
                    'subtotal'        => $itemSubtotal,
                ]);

                // Kurangi stok
                if ($product->track_stock) {
                    $product->updateStock(
                        -$item['qty'], 'out', auth()->user(),
                        $transaction->id,
                        "Penjualan #{$transaction->invoice_number}"
                    );
                }
            }

            DB::commit();

            return response()->json([
                'success'        => true,
                'message'        => 'Transaksi berhasil!',
                'invoice_number' => $transaction->invoice_number,
                'transaction_id' => $transaction->id,
                'grand_total'    => $transaction->grand_total,
                'change_amount'  => $transaction->change_amount,
            ]);

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

    /**
     * Struk transaksi
     */
    public function receipt(Transaction $transaction)
    {
        $transaction->load('items.product', 'user');
        $settings = [
            'store_name'    => Setting::get('store_name', 'Toko'),
            'store_address' => Setting::get('store_address', ''),
            'store_phone'   => Setting::get('store_phone', ''),
        ];
        return view('pos.receipt', compact('transaction', 'settings'));
    }

    /**
     * Halaman buka sesi kasir
     */
    public function openSession()
    {
        $activeSession = auth()->user()->getActiveSession();
        if ($activeSession) return redirect()->route('pos.index');

        // Cek apakah ada kasir lain yang sedang buka sesi
        $otherActiveSession = CashSession::where('status', 'open')->with('user')->first();
        
        return view('pos.open-session', compact('otherActiveSession'));
    }

    public function storeSession(Request $request)
    {
        $request->validate(['opening_cash' => 'required|numeric|min:0']);

        // Cek lagi apakah ada orang lain yang sedang buka sesi
        $otherActiveSession = CashSession::where('status', 'open')->first();
        if ($otherActiveSession && $otherActiveSession->user_id !== auth()->id()) {
            $otherActiveSession->load('user');
            return back()->with('error', 'Sesi kasir sedang dibuka oleh ' . $otherActiveSession->user->name . '. Silakan minta kasir tersebut untuk menutup sesi terlebih dahulu.');
        }

        // Tutup sesi lama user ini jika ada (fail-safe)
        CashSession::where('user_id', auth()->id())->where('status', 'open')
            ->update(['status' => 'closed', 'closed_at' => now()]);

        CashSession::create([
            'user_id'      => auth()->id(),
            'opening_cash' => $request->opening_cash,
            'opened_at'    => now(),
            'status'       => 'open',
        ]);

        return redirect()->route('pos.index')->with('success', 'Sesi kasir dibuka!');
    }

    /**
     * Tutup sesi kasir
     */
    public function closeSession(Request $request)
    {
        $request->validate(['closing_cash' => 'required|numeric|min:0']);

        $session = auth()->user()->getActiveSession();
        if (!$session) return response()->json(['success' => false, 'message' => 'Tidak ada sesi aktif']);

        $session->close($request->closing_cash, $request->notes ?? '');

        $data = [
            'success'         => true,
            'closing_cash'    => (float) $session->closing_cash,
            'expected_cash'   => (float) $session->expected_cash,
            'cash_difference' => (float) $session->cash_difference,
            'total_sales'     => (float) $session->total_sales,
            'total_cash'      => (float) $session->total_cash,
            'total_qris'      => (float) $session->total_qris,
            'total_transfer'  => (float) $session->total_transfer,
            'total_expenses'  => (float) $session->total_expenses,
            'total_purchases' => (float) $session->total_purchases,
        ];

        return response()->json($data);
    }

    /**
     * Ringkasan sesi untuk modal tutup kasir
     */
    public function sessionSummary()
    {
        $session = auth()->user()->getActiveSession();
        if (!$session) return response()->json(['error' => 'No active session']);

        $transactions = $session->transactions()->where('status', 'completed')->get();
        $expenses     = $session->expenses()->latest()->get();
        $purchases    = $session->purchases()->where('payment_status', 'paid')->with('supplier')->latest()->get();
        $voids        = $session->transactions()->where('status', 'void')->get();

        $data = [
            'session'   => $session,
            'total_trx' => $transactions->count(),
            'details'   => [
                'expenses'  => $expenses,
                'purchases' => $purchases,
                'voids'     => $voids
            ]
        ];

        // Blind Close: Sembunyikan total sales dari kasir (kecuali Admin/Manajer)
        if (auth()->user()->isManajer()) {
            $data['total_cash']      = (float) $session->total_cash;
            $data['total_transfer']  = (float) $session->total_transfer;
            $data['total_qris']      = (float) $session->total_qris;
            $data['total_sales']     = (float) $session->total_sales;
            $data['total_expenses']  = (float) $session->total_expenses;
            $data['total_purchases'] = (float) $session->total_purchases;
            $data['total_profit']    = (float) $transactions->sum(fn($t) => $t->profit);
        }

        return response()->json($data);
    }

    public function updatePrinterSettings(Request $request)
    {
        $request->validate([
            'printer_width'      => 'required|in:58,80',
            'printer_auto_print' => 'boolean',
            'printer_show_logo'  => 'boolean',
            'printer_type'       => 'nullable|string',
            'printer_font_size'  => 'nullable|in:xs,sm,base,lg',
        ]);

        Setting::set('printer_width', $request->printer_width);
        Setting::set('printer_auto_print', $request->boolean('printer_auto_print'));
        Setting::set('printer_show_logo', $request->boolean('printer_show_logo'));
        Setting::set('printer_type', $request->printer_type ?? 'thermal');
        Setting::set('printer_font_size', $request->printer_font_size ?? 'sm');

        return response()->json(['success' => true]);
    }

    /**
     * Riwayat transaksi kasir hari ini
     */
    public function history(Request $request)
    {
        $session = auth()->user()->getActiveSession();
        $query = Transaction::where('user_id', auth()->id())
            ->where('status', 'completed')
            ->with('items')
            ->latest('transaction_date');

        // Filter by current active session to keep history clean after "klerek"
        if ($session) {
            $query->where('cash_session_id', $session->id);
        } else {
            // If no active session (rare for this route due to middleware), show today's as fallback
            $query->whereDate('transaction_date', today());
        }

        $transactions = $query->paginate(20);
        return view('pos.history', compact('session', 'transactions'));
    }

    /**
     * Membatalkan transaksi (Void) dengan otorisasi
     */
    public function void(Request $request, Transaction $transaction)
    {
        if (!Setting::get('void_feature_enabled', false)) {
            return response()->json(['success' => false, 'message' => 'Fitur Void dinonaktifkan oleh Admin.'], 403);
        }

        $request->validate([
            'auth_password' => 'required',
            'reason'        => 'required|min:5'
        ]);

        $auth_user = User::whereIn('role', ['admin', 'manajer'])
            ->get()
            ->filter(fn($u) => \Hash::check($request->auth_password, $u->password))
            ->first();

        if (!$auth_user) {
            return response()->json(['success' => false, 'message' => 'Password Otorisasi salah atau Anda tidak memiliki akses.'], 401);
        }

        if ($transaction->status === 'void') {
            return response()->json(['success' => false, 'message' => 'Transaksi sudah dibatalkan sebelumnya.'], 422);
        }

        \DB::transaction(function () use ($transaction, $auth_user, $request) {
            foreach ($transaction->items as $item) {
                // Gunakan withTrashed agar tetap bisa mengembalikan stok walau produk dihapus dari menu
                $product = Product::withTrashed()->find($item->product_id);
                
                if ($product && $product->track_stock) {
                    $product->increment('stock', $item->quantity);
                    
                    // Catat mutasi stok (VOID)
                    StockMovement::create([
                        'product_id'      => $product->id,
                        'user_id'         => auth()->id(),
                        'transaction_id'  => $transaction->id,
                        'type'            => 'in',
                        'quantity_before' => $product->stock - $item->quantity,
                        'quantity_change' => $item->quantity,
                        'quantity_after'  => $product->stock,
                        'reason'          => 'Pembatalan Transaksi (VOID): ' . $transaction->invoice_number,
                    ]);
                }
            }

            // Simpan log void untuk laporan klerekan
            \App\Models\VoidLog::create([
                'user_id'       => auth()->id(),
                'authorized_by' => $auth_user->id,
                'type'          => 'transaksi',
                'product_name'  => 'Transaksi: ' . $transaction->invoice_number,
                'quantity'      => $transaction->items->count(),
                'amount'        => $transaction->grand_total,
                'reason'        => $request->reason
            ]);

            $transaction->update([
                'status'        => 'void',
                'voided_at'     => now(),
                'voided_by'     => auth()->id(),
                'authorized_by' => $auth_user->id,
                'void_reason'   => $request->reason
            ]);
        });

        return response()->json(['success' => true, 'message' => 'Transaksi berhasil dibatalkan.']);
    }

    /**
     * Verifikasi otoritas Admin/Manajer (untuk Void Item dll)
     */
    public function verifyAuthority(Request $request)
    {
        $request->validate(['password' => 'required']);

        $auth_user = User::whereIn('role', ['admin', 'manajer'])
            ->get()
            ->filter(fn($u) => \Hash::check($request->password, $u->password))
            ->first();

        if ($auth_user) {
            // Simpan log void jika ada data
            if ($request->has('log_data')) {
                $log = $request->log_data;
                \App\Models\VoidLog::create([
                    'user_id'       => auth()->id(),
                    'authorized_by' => $auth_user->id,
                    'type'          => $log['type'] ?? 'item',
                    'product_name'  => $log['product_name'] ?? null,
                    'quantity'      => $log['quantity'] ?? 1,
                    'amount'        => $log['amount'] ?? 0,
                    'reason'        => $request->reason
                ]);
            }

            return response()->json(['success' => true]);
        }

        return response()->json(['success' => false, 'message' => 'Password Otorisasi salah.'], 401);
    }

    /**
     * Simpan stok masuk dari suplier
     */
    public function restock(Request $request)
    {
        $request->validate([
            'product_id'     => 'required|exists:products,id',
            'quantity'       => 'required|integer|min:1',
            'cost_price'     => 'required|numeric|min:0',
            'supplier_name'  => 'required|string',
            'payment_status' => 'required|in:paid,debt',
            'due_date'       => 'nullable|date',
        ]);

        return DB::transaction(function() use ($request) {
            $product = Product::findOrFail($request->product_id);
            $session = auth()->user()->getActiveSession();
            
            // 1. Cari atau buat suplier
            $supplier = Supplier::firstOrCreate(['name' => $request->supplier_name]);

            // 2. Buat record Purchase
            $purchase = Purchase::create([
                'invoice_number' => 'PUR-' . now()->format('YmdHis') . rand(10, 99),
                'supplier_id'    => $supplier->id,
                'user_id'        => auth()->id(),
                'cash_session_id'=> $session?->id,
                'purchase_date'  => now(),
                'total_amount'   => $request->quantity * $request->cost_price,
                'payment_status' => $request->payment_status,
                'payment_method' => $request->payment_status === 'paid' ? 'cash' : null,
                'due_date'       => $request->payment_status === 'debt' ? $request->due_date : null,
            ]);

            // 3. Buat Purchase Item
            $purchase->items()->create([
                'product_id'   => $product->id,
                'product_name' => $product->name,
                'quantity'     => $request->quantity,
                'cost_price'   => $request->cost_price,
                'subtotal'     => $request->quantity * $request->cost_price,
            ]);

            // 4. Update Stok & Cost Price Produk & Catat Movement
            $product->updateStock(
                $request->quantity, 
                'in', 
                auth()->user(), 
                null, 
                "Pembelian dari {$supplier->name} (#{$purchase->invoice_number})"
            );
            $product->update(['cost_price' => $request->cost_price]);

            return response()->json(['success' => true]);
        });
    }

    /**
     * Simpan pengeluaran harian
     */
    public function expense(Request $request)
    {
        $request->validate([
            'amount'      => 'required|numeric|min:0',
            'category'    => 'required|string',
            'description' => 'required|string',
        ]);

        $session = auth()->user()->getActiveSession();

        Expense::create([
            'user_id'         => auth()->id(),
            'cash_session_id' => $session?->id,
            'amount'          => $request->amount,
            'category'        => $request->category,
            'description'     => $request->description,
            'expense_date'    => now(),
        ]);

        return response()->json(['success' => true]);
    }
}
