<?php

namespace App\Http\Controllers;

use App\Models\Purchase;
use App\Models\PurchaseItem;
use App\Models\Party;
use App\Models\Item;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\DB;

class PurchaseController extends Controller
{
    /**
     * Display a listing of purchases.
     */
    public function index(Request $request): View
    {
        $query = Purchase::with(['party', 'items.item']);

        // Filter by party
        if ($request->filled('party_id')) {
            $query->where('party_id', $request->party_id);
        }

        // Filter by date range
        if ($request->filled('from_date')) {
            $query->whereDate('date', '>=', $request->from_date);
        }
        if ($request->filled('to_date')) {
            $query->whereDate('date', '<=', $request->to_date);
        }

        // Search by bill no
        if ($request->filled('search')) {
            $query->where('bill_no', 'like', '%' . $request->search . '%');
        }

        $purchases = $query->orderBy('date', 'desc')->orderBy('id', 'desc')->get();
        $parties = Party::suppliers()->active()->orderBy('name')->get();

        return view('purchases.index', compact('purchases', 'parties'));
    }

    /**
     * Show the form for creating a new purchase.
     */
    public function create(): View
    {
        $parties = Party::suppliers()->active()->orderBy('name')->get();
        $items = Item::where('is_active', true)->orderBy('name')->get();
        $nextBillNo = Purchase::generateBillNo();

        return view('purchases.create', compact('parties', 'items', 'nextBillNo'));
    }

    /**
     * Store a newly created purchase.
     */
    public function store(Request $request): RedirectResponse
    {
        $validated = $request->validate([
            'party_id' => 'required|exists:parties,id',
            'date' => 'required|date',
            'bill_no' => 'required|string|max:50|unique:purchases,bill_no',
            'ref_no' => 'nullable|string|max:50',
            'remarks' => 'nullable|string|max:255',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:items,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.rate' => 'required|numeric|min:0',
        ]);

        DB::beginTransaction();
        try {
            // Create purchase
            $purchase = Purchase::create([
                'party_id' => $validated['party_id'],
                'date' => $validated['date'],
                'bill_no' => $validated['bill_no'],
                'ref_no' => $validated['ref_no'] ?? null,
                'remarks' => $validated['remarks'] ?? null,
                'gross_amount' => 0,
                'discount_amount' => $request->discount_amount ?? 0,
                'net_amount' => 0,
                'paid_amount' => $request->paid_amount ?? 0,
                'status' => 'posted',
            ]);

            // Add items
            $grossAmount = 0;
            foreach ($validated['items'] as $itemData) {
                $amount = $itemData['quantity'] * $itemData['rate'];
                $grossAmount += $amount;

                PurchaseItem::create([
                    'purchase_id' => $purchase->id,
                    'item_id' => $itemData['item_id'],
                    'quantity' => $itemData['quantity'],
                    'rate' => $itemData['rate'],
                    'amount' => $amount,
                ]);

                // Update item stock
                $item = Item::find($itemData['item_id']);
                $item->addStock($itemData['quantity']);
            }

            // Update totals
            $purchase->gross_amount = $grossAmount;
            $purchase->net_amount = $grossAmount - ($request->discount_amount ?? 0);
            $purchase->balance_amount = $purchase->net_amount - ($request->paid_amount ?? 0);
            $purchase->save();

            // Post to ledger
            $purchase->postToLedger();

            DB::commit();

            return redirect()->route('purchases.index')
                ->with('success', 'Purchase bill created successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->withInput()
                ->with('error', 'Error creating purchase: ' . $e->getMessage());
        }
    }

    /**
     * Display the specified purchase.
     */
    public function show(Purchase $purchase): View
    {
        $purchase->load(['party', 'items.item']);
        
        return view('purchases.show', compact('purchase'));
    }

    /**
     * Show the form for editing the specified purchase.
     */
    public function edit(Purchase $purchase): View
    {
        $purchase->load(['party', 'items.item']);
        $parties = Party::suppliers()->active()->orderBy('name')->get();
        $items = Item::where('is_active', true)->orderBy('name')->get();

        return view('purchases.edit', compact('purchase', 'parties', 'items'));
    }

    /**
     * Update the specified purchase.
     */
    public function update(Request $request, Purchase $purchase): RedirectResponse
    {
        $validated = $request->validate([
            'party_id' => 'required|exists:parties,id',
            'date' => 'required|date',
            'ref_no' => 'nullable|string|max:50',
            'remarks' => 'nullable|string|max:255',
            'items' => 'required|array|min:1',
            'items.*.item_id' => 'required|exists:items,id',
            'items.*.quantity' => 'required|numeric|min:0.01',
            'items.*.rate' => 'required|numeric|min:0',
        ]);

        DB::beginTransaction();
        try {
            // Reverse old stock and ledger
            $purchase->reverseStock();
            $purchase->reverseLedger();

            // Delete old items
            $purchase->items()->delete();

            // Update purchase
            $purchase->update([
                'party_id' => $validated['party_id'],
                'date' => $validated['date'],
                'ref_no' => $validated['ref_no'] ?? null,
                'remarks' => $validated['remarks'] ?? null,
                'discount_amount' => $request->discount_amount ?? 0,
                'paid_amount' => $request->paid_amount ?? 0,
            ]);

            // Add new items
            $grossAmount = 0;
            foreach ($validated['items'] as $itemData) {
                $amount = $itemData['quantity'] * $itemData['rate'];
                $grossAmount += $amount;

                PurchaseItem::create([
                    'purchase_id' => $purchase->id,
                    'item_id' => $itemData['item_id'],
                    'quantity' => $itemData['quantity'],
                    'rate' => $itemData['rate'],
                    'amount' => $amount,
                ]);

                // Update item stock
                $item = Item::find($itemData['item_id']);
                $item->addStock($itemData['quantity']);
            }

            // Update totals
            $purchase->gross_amount = $grossAmount;
            $purchase->net_amount = $grossAmount - ($request->discount_amount ?? 0);
            $purchase->balance_amount = $purchase->net_amount - ($request->paid_amount ?? 0);
            $purchase->save();

            // Post to ledger
            $purchase->postToLedger();

            DB::commit();

            return redirect()->route('purchases.index')
                ->with('success', 'Purchase bill updated successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->back()
                ->withInput()
                ->with('error', 'Error updating purchase: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified purchase.
     */
    public function destroy(Purchase $purchase): RedirectResponse
    {
        DB::beginTransaction();
        try {
            // Reverse stock and ledger
            $purchase->reverseStock();
            $purchase->reverseLedger();

            // Delete items and purchase
            $purchase->items()->delete();
            $purchase->delete();

            DB::commit();

            return redirect()->route('purchases.index')
                ->with('success', 'Purchase bill deleted successfully.');

        } catch (\Exception $e) {
            DB::rollBack();
            return redirect()->route('purchases.index')
                ->with('error', 'Error deleting purchase: ' . $e->getMessage());
        }
    }

    /**
     * Print purchase bill.
     */
    public function print(Purchase $purchase): View
    {
        $purchase->load(['party', 'items.item']);
        
        return view('purchases.print', compact('purchase'));
    }
}
