<?php

namespace App\Http\Controllers;

use App\Models\Currency;
use App\Models\Customer;
use App\Models\Invoice;
use App\Models\Payment;
use App\Models\Product;
use App\Models\StockMovement;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class InvoiceController extends Controller
{
    public function index(Request $request) { $invoices = Invoice::with('customer')->when($request->search, fn ($q, $s) => $q->where('invoice_number', 'like', "%{$s}%")->orWhereHas('customer', fn ($c) => $c->where('name', 'like', "%{$s}%")))->latest('invoice_date')->paginate(15); return view('invoices.index', compact('invoices')); }
    public function create()
    {
        $products = Product::where('is_active', true)->orderBy('name')->get();

        return view('invoices.create', [
            'customers' => Customer::orderBy('name')->get(),
            'products' => $products,
            'productsForSale' => $products->map(fn (Product $product) => [
                'id' => $product->id,
                'name' => $product->name,
                'sku' => $product->sku,
                'stock' => $product->stock_quantity,
                'retail' => (float) $product->retail_price,
                'wholesale' => (float) $product->wholesale_price,
            ])->values(),
            'currencies' => Currency::where('is_active', true)->orderByDesc('is_default')->get(),
        ]);
    }
    public function store(Request $request) {
        $data = $request->validate(['customer_id' => ['nullable', 'exists:customers,id'], 'walk_in_name' => ['nullable', 'string', 'max:120'], 'walk_in_phone' => ['nullable', 'string', 'max:30'], 'sale_type' => ['required', 'in:retail,wholesale'], 'currency_code' => ['required', 'exists:currencies,code'], 'discount' => ['nullable', 'numeric', 'min:0'], 'paid_amount' => ['nullable', 'numeric', 'min:0'], 'payment_method' => ['nullable', 'in:cash,bank,mobile,other'], 'invoice_date' => ['required', 'date'], 'notes' => ['nullable', 'string'], 'items' => ['required', 'array', 'min:1'], 'items.*.product_id' => ['required', 'exists:products,id'], 'items.*.quantity' => ['required', 'numeric', 'gt:0']]);
        $invoice = DB::transaction(function () use ($data, $request) {
            $currency = Currency::where('code', $data['currency_code'])->firstOrFail(); $subtotal = 0; $lines = [];
            foreach ($data['items'] as $entry) { $product = Product::lockForUpdate()->findOrFail($entry['product_id']); if ((float) $product->stock_quantity < (float) $entry['quantity']) throw \Illuminate\Validation\ValidationException::withMessages(['items' => __('Not enough stock for :product.', ['product' => $product->name])]); $price = $product->priceFor($data['sale_type']); $line = round($price * $entry['quantity'], 2); $subtotal += $line; $lines[] = compact('product', 'price', 'line', 'entry'); }
            $discount = (float) ($data['discount'] ?? 0); $total = max(0, $subtotal - $discount); $paid = min($total, (float) ($data['paid_amount'] ?? 0)); $due = $total - $paid;
            $invoice = Invoice::create(['invoice_number' => 'INV-'.now()->format('ymd').'-'.str_pad((string) (Invoice::whereDate('created_at', today())->count() + 1), 3, '0', STR_PAD_LEFT), 'customer_id' => $data['customer_id'], 'walk_in_name' => $data['customer_id'] ? null : ($data['walk_in_name'] ?? null), 'walk_in_phone' => $data['customer_id'] ? null : ($data['walk_in_phone'] ?? null), 'user_id' => auth()->id(), 'sale_type' => $data['sale_type'], 'currency_code' => $currency->code, 'exchange_rate' => $currency->exchange_rate, 'subtotal' => $subtotal, 'discount' => $discount, 'total' => $total, 'paid_amount' => $paid, 'due_amount' => $due, 'status' => $due <= 0 ? 'paid' : ($paid > 0 ? 'partial' : 'unpaid'), 'invoice_date' => $data['invoice_date'], 'notes' => $data['notes']]);
            foreach ($lines as $row) { $invoice->items()->create(['product_id' => $row['product']->id, 'product_name' => $row['product']->name, 'quantity' => $row['entry']['quantity'], 'unit_price' => $row['price'], 'cost_price' => $row['product']->cost_price, 'line_total' => $row['line']]); $row['product']->decrement('stock_quantity', $row['entry']['quantity']); StockMovement::create(['product_id' => $row['product']->id, 'invoice_id' => $invoice->id, 'type' => 'sale', 'quantity' => -$row['entry']['quantity'], 'note' => $invoice->invoice_number]); }
            if ($paid > 0) Payment::create(['invoice_id' => $invoice->id, 'customer_id' => $invoice->customer_id, 'amount' => $paid, 'currency_code' => $currency->code, 'method' => $data['payment_method'] ?? 'cash', 'payment_date' => $data['invoice_date']]);
            return $invoice;
        });
        return redirect()->route('invoices.show', $invoice)->with('success', __('Invoice created successfully.'));
    }
    public function show(Invoice $invoice) { $invoice->load('customer', 'items.product', 'payments'); return view('invoices.show', compact('invoice')); }
    public function payment(Request $request, Invoice $invoice) { $data = $request->validate(['amount' => ['required', 'numeric', 'gt:0', 'max:'.$invoice->due_amount], 'method' => ['required', 'in:cash,bank,mobile,other'], 'payment_date' => ['required', 'date'], 'reference' => ['nullable', 'string', 'max:100']]); Payment::create($data + ['invoice_id' => $invoice->id, 'customer_id' => $invoice->customer_id, 'currency_code' => $invoice->currency_code]); $invoice->increment('paid_amount', $data['amount']); $invoice->decrement('due_amount', $data['amount']); $invoice->refresh(); $invoice->update(['status' => $invoice->due_amount <= 0 ? 'paid' : 'partial']); return back()->with('success', __('Payment recorded.')); }
}
