<?php

namespace App\Http\Controllers;

use App\Models\Purchase;
use App\Models\Supplier;
use App\Models\Warehouse;
use App\Models\Product;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;

class PurchaseController extends Controller
{
    /**
     * Display a listing of purchases.
     */
    public function index(Request $request)
    {
        $query = Purchase::with(['supplier', 'warehouse', 'items'])
            ->latest();
        
        // Apply filters
        if ($request->filled('status')) {
            $query->where('status', $request->status);
        }
        
        if ($request->filled('supplier_id')) {
            $query->where('supplier_id', $request->supplier_id);
        }
        
        if ($request->filled('warehouse_id')) {
            $query->where('warehouse_id', $request->warehouse_id);
        }
        
        if ($request->filled('payment_status')) {
            $query->where('payment_status', $request->payment_status);
        }
        
        if ($request->filled('start_date') && $request->filled('end_date')) {
            $query->whereBetween('purchase_date', [$request->start_date, $request->end_date]);
        }
        
        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function($q) use ($search) {
                $q->where('purchase_code', 'like', "%{$search}%")
                  ->orWhere('reference_no', 'like', "%{$search}%")
                  ->orWhereHas('supplier', function($q) use ($search) {
                      $q->where('name', 'like', "%{$search}%")
                        ->orWhere('phone', 'like', "%{$search}%");
                  });
            });
        }
        
        $purchases = $query->paginate(20);
        
        // Get filter data
        $suppliers = Supplier::where('status', 'active')->orderBy('name')->get();
        $warehouses = Warehouse::where('status', 'active')->orderBy('name')->get();
        
        // Calculate stats
        $stats = [
            'total_purchases' => Purchase::count(),
            'total_amount' => Purchase::sum('grand_total'),
            'total_due' => Purchase::whereIn('payment_status', ['due', 'partial'])->sum('due_amount'),
            'pending_purchases' => Purchase::where('status', 'pending')->count(),
        ];
        
        return view('purchases.index', compact('purchases', 'suppliers', 'warehouses', 'stats'));
    }
    
    /**
     * Show the form for creating a new purchase.
     */
    public function create()
    {
        $suppliers = Supplier::where('status', 'active')->orderBy('name')->get();
        $warehouses = Warehouse::where('status', 'active')->orderBy('name')->get();
        $products = Product::orderBy('name')->get();
        
        return view('purchases.create', compact('suppliers', 'warehouses', 'products'));
    }
    
    /**
     * Store a newly created purchase in storage.
     */
    public function store(Request $request)
    {
        // Validation
        $request->validate([
            'supplier_id' => 'required|exists:suppliers,id',
            'purchase_date' => 'required|date',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_cost' => 'required|numeric|min:0',
        ]);
        
        DB::beginTransaction();
        
        try {
            // Generate purchase code
            $purchaseCode = $this->generatePurchaseCode();
            
            // Calculate totals
            $subtotal = 0;
            $totalQuantity = 0;
            $totalItems = count($request->items);
            
            foreach ($request->items as $item) {
                $itemTotal = $item['quantity'] * $item['unit_cost'];
                $subtotal += $itemTotal;
                $totalQuantity += $item['quantity'];
            }
            
            $taxAmount = $subtotal * ($request->tax_rate ?? 0) / 100;
            $discountAmount = $request->discount_amount ?? 0;
            $shippingCost = $request->shipping_cost ?? 0;
            $grandTotal = $subtotal + $taxAmount + $shippingCost - $discountAmount;
            
            $paidAmount = $request->paid_amount ?? 0;
            $dueAmount = max(0, $grandTotal - $paidAmount);
            
            $paymentStatus = $dueAmount == 0 ? 'paid' : ($paidAmount > 0 ? 'partial' : 'due');
            
            // Create purchase
            $purchase = Purchase::create([
                'purchase_code' => $purchaseCode,
                'purchase_date' => $request->purchase_date,
                'supplier_id' => $request->supplier_id,
                'warehouse_id' => $request->warehouse_id,
                'total_items' => $totalItems,
                'total_quantity' => $totalQuantity,
                'subtotal' => $subtotal,
                'discount_amount' => $discountAmount,
                'tax_amount' => $taxAmount,
                'shipping_cost' => $shippingCost,
                'grand_total' => $grandTotal,
                'paid_amount' => $paidAmount,
                'due_amount' => $dueAmount,
                'payment_status' => $paymentStatus,
                'payment_method' => $request->payment_method,
                'reference_no' => $request->reference_no,
                'notes' => $request->notes,
                'status' => $request->status ?? 'pending',
                'created_by' => auth()->id(),
            ]);
            
            // Create purchase items
            foreach ($request->items as $item) {
                $product = Product::find($item['product_id']);
                
                $purchase->items()->create([
                    'product_id' => $item['product_id'],
                    'product_code' => $product->code,
                    'product_name' => $product->name,
                    'quantity' => $item['quantity'],
                    'received_quantity' => $item['received_quantity'] ?? 0,
                    'pending_quantity' => $item['quantity'] - ($item['received_quantity'] ?? 0),
                    'unit_cost' => $item['unit_cost'],
                    'unit_price' => $product->selling_price,
                    'tax_rate' => $request->tax_rate ?? 0,
                    'discount_rate' => $item['discount_rate'] ?? 0,
                    'total_cost' => $item['quantity'] * $item['unit_cost'],
                    'expiry_date' => $item['expiry_date'] ?? null,
                    'batch_no' => $item['batch_no'] ?? null,
                    'status' => ($item['received_quantity'] ?? 0) > 0 ? 'partial' : 'pending',
                ]);
            }
            
            // Update product stock if status is received
            if ($request->status == 'received') {
                foreach ($request->items as $item) {
                    $product = Product::find($item['product_id']);
                    $receivedQty = $item['received_quantity'] ?? $item['quantity'];
                    $product->stock_quantity += $receivedQty;
                    $product->cost_price = $item['unit_cost'];
                    $product->save();
                }
            }
            
            DB::commit();
            
            return redirect()->route('purchases.index')
                ->with('success', 'Purchase created successfully!');
                
        } catch (\Exception $e) {
            DB::rollBack();
            
            return redirect()->back()
                ->with('error', 'Failed to create purchase: ' . $e->getMessage())
                ->withInput();
        }
    }
    
    /**
     * Display the specified purchase.
     */
    public function show(Purchase $purchase)
    {
        $purchase->load(['supplier', 'items.product', 'warehouse', 'creator']);
        return view('purchases.show', compact('purchase'));
    }
    
    /**
     * Show the form for editing the specified purchase.
     */
    public function edit(Purchase $purchase)
    {
        $purchase->load(['items.product']);
        $suppliers = Supplier::where('status', 'active')->orderBy('name')->get();
        $warehouses = Warehouse::where('status', 'active')->orderBy('name')->get();
        $products = Product::orderBy('name')->get();
        
        return view('purchases.edit', compact('purchase', 'suppliers', 'warehouses', 'products'));
    }
    
    /**
     * Update the specified purchase in storage.
     */
    public function update(Request $request, Purchase $purchase)
    {
        if ($purchase->status != 'pending') {
            return redirect()->back()->with('error', 'Only pending purchases can be updated!');
        }
        
        $request->validate([
            'supplier_id' => 'required|exists:suppliers,id',
            'purchase_date' => 'required|date',
            'items' => 'required|array|min:1',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.unit_cost' => 'required|numeric|min:0',
        ]);
        
        DB::beginTransaction();
        
        try {
            // Delete existing items
            $purchase->items()->delete();
            
            // Calculate totals
            $subtotal = 0;
            $totalQuantity = 0;
            $totalItems = count($request->items);
            
            foreach ($request->items as $item) {
                $itemTotal = $item['quantity'] * $item['unit_cost'];
                $subtotal += $itemTotal;
                $totalQuantity += $item['quantity'];
            }
            
            $taxAmount = $subtotal * ($request->tax_rate ?? 0) / 100;
            $discountAmount = $request->discount_amount ?? 0;
            $shippingCost = $request->shipping_cost ?? 0;
            $grandTotal = $subtotal + $taxAmount + $shippingCost - $discountAmount;
            
            $paidAmount = $request->paid_amount ?? 0;
            $dueAmount = max(0, $grandTotal - $paidAmount);
            
            $paymentStatus = $dueAmount == 0 ? 'paid' : ($paidAmount > 0 ? 'partial' : 'due');
            
            // Update purchase
            $purchase->update([
                'purchase_date' => $request->purchase_date,
                'supplier_id' => $request->supplier_id,
                'warehouse_id' => $request->warehouse_id,
                'total_items' => $totalItems,
                'total_quantity' => $totalQuantity,
                'subtotal' => $subtotal,
                'discount_amount' => $discountAmount,
                'tax_amount' => $taxAmount,
                'shipping_cost' => $shippingCost,
                'grand_total' => $grandTotal,
                'paid_amount' => $paidAmount,
                'due_amount' => $dueAmount,
                'payment_status' => $paymentStatus,
                'payment_method' => $request->payment_method,
                'reference_no' => $request->reference_no,
                'notes' => $request->notes,
                'updated_by' => auth()->id(),
            ]);
            
            // Create new items
            foreach ($request->items as $item) {
                $product = Product::find($item['product_id']);
                
                $purchase->items()->create([
                    'product_id' => $item['product_id'],
                    'product_code' => $product->code,
                    'product_name' => $product->name,
                    'quantity' => $item['quantity'],
                    'received_quantity' => $item['received_quantity'] ?? 0,
                    'pending_quantity' => $item['quantity'] - ($item['received_quantity'] ?? 0),
                    'unit_cost' => $item['unit_cost'],
                    'unit_price' => $product->selling_price,
                    'tax_rate' => $request->tax_rate ?? 0,
                    'discount_rate' => $item['discount_rate'] ?? 0,
                    'total_cost' => $item['quantity'] * $item['unit_cost'],
                    'expiry_date' => $item['expiry_date'] ?? null,
                    'batch_no' => $item['batch_no'] ?? null,
                    'status' => ($item['received_quantity'] ?? 0) > 0 ? 'partial' : 'pending',
                ]);
            }
            
            DB::commit();
            
            return redirect()->route('purchases.show', $purchase)
                ->with('success', 'Purchase updated successfully!');
                
        } catch (\Exception $e) {
            DB::rollBack();
            
            return redirect()->back()
                ->with('error', 'Failed to update purchase: ' . $e->getMessage())
                ->withInput();
        }
    }
    
    /**
     * Remove the specified purchase from storage.
     */
    public function destroy(Purchase $purchase)
    {
        if ($purchase->status != 'pending') {
            return redirect()->back()->with('error', 'Only pending purchases can be deleted!');
        }
        
        $purchase->delete();
        
        return redirect()->route('purchases.index')
            ->with('success', 'Purchase deleted successfully!');
    }
    
    /**
     * Mark purchase as received.
     */
    public function receive(Purchase $purchase)
    {
        if ($purchase->status == 'received') {
            return redirect()->back()->with('error', 'Purchase already received!');
        }
        
        DB::beginTransaction();
        
        try {
            $purchase->update([
                'status' => 'received',
                'received_date' => now(),
            ]);
            
            // Update stock quantities
            foreach ($purchase->items as $item) {
                $item->update([
                    'received_quantity' => $item->quantity,
                    'pending_quantity' => 0,
                    'status' => 'received'
                ]);
                
                // Update product stock
                if ($item->product) {
                    $item->product->increment('stock_quantity', $item->quantity);
                }
            }
            
            DB::commit();
            
            return redirect()->back()->with('success', 'Purchase marked as received successfully!');
            
        } catch (\Exception $e) {
            DB::rollBack();
            
            return redirect()->back()->with('error', 'Failed to receive purchase: ' . $e->getMessage());
        }
    }
    
    /**
     * Cancel purchase.
     */
    public function cancel(Purchase $purchase)
    {
        if ($purchase->status == 'cancelled') {
            return redirect()->back()->with('error', 'Purchase already cancelled!');
        }
        
        if ($purchase->status == 'received') {
            return redirect()->back()->with('error', 'Cannot cancel received purchase!');
        }
        
        $purchase->update([
            'status' => 'cancelled',
            'notes' => ($purchase->notes ?? '') . "\n\nCancelled on " . now()->format('Y-m-d H:i:s')
        ]);
        
        return redirect()->back()->with('success', 'Purchase cancelled successfully!');
    }
    
    /**
     * Show purchase invoice.
     */
    public function invoice(Purchase $purchase)
    {
        $purchase->load([
            'supplier',
            'warehouse',
            'items.product',
            'creator'
        ]);
        
        return view('purchases.invoice', compact('purchase'));
    }
    
    /**
     * Print purchase invoice.
     */
    public function printInvoice(Purchase $purchase)
    {
        $purchase->load([
            'supplier',
            'warehouse',
            'items.product',
            'creator'
        ]);
        
        return view('purchases.print-invoice', compact('purchase'));
    }
    
    /**
     * Generate purchase code.
     */
    private function generatePurchaseCode()
    {
        $prefix = 'PUR-';
        $year = date('Y');
        $month = date('m');
        
        $lastPurchase = Purchase::where('purchase_code', 'like', "{$prefix}{$year}-{$month}-%")
            ->orderBy('purchase_code', 'desc')
            ->first();
        
        if ($lastPurchase) {
            $lastNumber = intval(substr($lastPurchase->purchase_code, -3));
            $nextNumber = str_pad($lastNumber + 1, 3, '0', STR_PAD_LEFT);
        } else {
            $nextNumber = '001';
        }
        
        return "{$prefix}{$year}-{$month}-{$nextNumber}";
    }
}