<?php

namespace App\Http\Controllers;

use App\Models\Currency;
use App\Models\Product;
use App\Models\Purchase;
use App\Models\StockMovement;
use App\Models\Supplier;
use App\Models\SupplierPayment;
use App\Models\Unit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;

class PurchaseController extends Controller
{
    public function index(Request $request) { $purchases = Purchase::with('supplier')->when($request->search, fn ($q, $s) => $q->where('purchase_number', 'like', "%{$s}%")->orWhereHas('supplier', fn ($x) => $x->where('name', 'like', "%{$s}%")))->latest('purchase_date')->paginate(15); return view('purchases.index', compact('purchases')); }
    public function create() {
        $products = Product::where('is_active', true)->orderBy('name')->get();
        $units = Unit::orderBy('name')->get();
        return view('purchases.create', ['suppliers' => Supplier::orderBy('name')->get(), 'productsForPurchase' => $products->map(fn (Product $product) => ['id' => $product->id, 'name' => $product->name, 'sku' => $product->sku, 'unit' => $product->unit, 'cost' => (float) $product->cost_price])->values(), 'unitsForPurchase' => $units->map(fn (Unit $unit) => ['short' => $unit->short_name, 'name' => $unit->name])->values(), 'currencies' => Currency::where('is_active', true)->orderByDesc('is_default')->get()]);
    }
    public function store(Request $request) {
        $data = $request->validate(['supplier_id' => ['nullable', 'exists:suppliers,id'], 'currency_code' => ['required', 'exists:currencies,code'], 'paid_amount' => ['nullable', 'numeric', 'min:0'], 'payment_method' => ['nullable', 'in:cash,bank,mobile,other'], 'purchase_date' => ['required', 'date'], 'notes' => ['nullable', 'string'], 'items' => ['required', 'array', 'min:1'], 'items.*.product_id' => ['nullable', 'exists:products,id'], 'items.*.product_name' => ['nullable', 'string', 'max:120'], 'items.*.unit' => ['required', 'exists:units,short_name'], 'items.*.quantity' => ['required', 'numeric', 'gt:0'], 'items.*.unit_cost' => ['required', 'numeric', 'min:0']]);
        $purchase = DB::transaction(function () use ($data) {
            $currency = Currency::where('code', $data['currency_code'])->firstOrFail(); $lines = []; $subtotal = 0;
            foreach ($data['items'] as $row) { if (empty($row['product_id']) && empty($row['product_name'])) throw \Illuminate\Validation\ValidationException::withMessages(['items' => __('Choose a product or type a new product name.')]); $product = !empty($row['product_id']) ? Product::lockForUpdate()->findOrFail($row['product_id']) : Product::create(['sku' => 'PUR-'.strtoupper(Str::random(6)), 'name' => $row['product_name'], 'unit' => $row['unit'], 'cost_price' => $row['unit_cost'], 'retail_price' => $row['unit_cost'] * 1.20, 'wholesale_price' => $row['unit_cost'] * 1.10, 'stock_quantity' => 0, 'low_stock_at' => 0]); $total = round($row['quantity'] * $row['unit_cost'], 2); $subtotal += $total; $lines[] = compact('row', 'product', 'total'); }
            $paid = min($subtotal, (float) ($data['paid_amount'] ?? 0)); $due = $subtotal - $paid;
            $purchase = Purchase::create(['purchase_number' => 'PUR-'.now()->format('ymd').'-'.str_pad((string) (Purchase::whereDate('created_at', today())->count()+1),3,'0',STR_PAD_LEFT), 'supplier_id' => $data['supplier_id'], 'user_id' => auth()->id(), 'currency_code' => $currency->code, 'exchange_rate' => $currency->exchange_rate, 'subtotal' => $subtotal, 'paid_amount' => $paid, 'due_amount' => $due, 'status' => $due <= 0 ? 'paid' : ($paid ? 'partial' : 'unpaid'), 'purchase_date' => $data['purchase_date'], 'notes' => $data['notes']]);
            foreach ($lines as $line) { $purchase->items()->create(['product_id' => $line['product']->id, 'product_name' => $line['product']->name, 'unit' => $line['row']['unit'], 'quantity' => $line['row']['quantity'], 'unit_cost' => $line['row']['unit_cost'], 'line_total' => $line['total']]); $line['product']->increment('stock_quantity', $line['row']['quantity']); $line['product']->update(['cost_price' => $line['row']['unit_cost'], 'unit' => $line['row']['unit']]); StockMovement::create(['product_id' => $line['product']->id, 'type' => 'purchase', 'quantity' => $line['row']['quantity'], 'note' => $purchase->purchase_number]); }
            if ($paid && $data['supplier_id']) SupplierPayment::create(['supplier_id' => $data['supplier_id'], 'purchase_id' => $purchase->id, 'amount' => $paid, 'currency_code' => $currency->code, 'method' => $data['payment_method'] ?? 'cash', 'payment_date' => $data['purchase_date']]);
            return $purchase;
        });
        return redirect()->route('purchases.show', $purchase)->with('success', __('Purchase received and stock updated.'));
    }
    public function show(Purchase $purchase) { $purchase->load('supplier', 'items', 'payments'); return view('purchases.show', compact('purchase')); }
    public function payment(Request $request, Purchase $purchase) { $data = $request->validate(['amount' => ['required', 'numeric', 'gt:0', 'max:'.$purchase->due_amount], 'method' => ['required', 'in:cash,bank,mobile,other'], 'payment_date' => ['required', 'date'], 'reference' => ['nullable', 'string', 'max:100']]); if (! $purchase->supplier_id) return back()->withErrors(['supplier' => __('A supplier is required to record a payment.')]); SupplierPayment::create($data + ['supplier_id' => $purchase->supplier_id, 'purchase_id' => $purchase->id, 'currency_code' => $purchase->currency_code]); $purchase->increment('paid_amount', $data['amount']); $purchase->decrement('due_amount', $data['amount']); $purchase->refresh(); $purchase->update(['status' => $purchase->due_amount <= 0 ? 'paid' : 'partial']); return back()->with('success', __('Supplier payment recorded.')); }
}
