<?php

namespace App\Http\Controllers;

use App\Models\Sale;
use App\Models\Party;
use App\Models\Item;
use App\Models\Account;
use Illuminate\Http\Request;
use Illuminate\View\View;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;

class SaleController extends Controller
{
    /**
     * Display a listing of sales.
     */
    public function index(Request $request): View
    {
        $query = Sale::with(['party', 'user'])->latest('date');
        
        // 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);
        }
        
        // Filter by party
        if ($request->filled('party_id')) {
            $query->where('party_id', $request->party_id);
        }
        
        // Search by bill_no or ref_no
        if ($request->filled('search')) {
            $search = $request->search;
            $query->where(function($q) use ($search) {
                $q->where('bill_no', 'like', "%{$search}%")
                  ->orWhere('ref_no', 'like', "%{$search}%");
            });
        }
        
        $sales = $query->paginate(20)->withQueryString();
        $parties = Party::customers()->orderBy('name')->get();
        
        // Summary totals
        $summaryQuery = Sale::query();
        if ($request->filled('from_date')) {
            $summaryQuery->whereDate('date', '>=', $request->from_date);
        }
        if ($request->filled('to_date')) {
            $summaryQuery->whereDate('date', '<=', $request->to_date);
        }
        if ($request->filled('party_id')) {
            $summaryQuery->where('party_id', $request->party_id);
        }
        
        $totals = [
            'gross' => $summaryQuery->sum('sub_total'),
            'discount' => $summaryQuery->sum('discount_amount'),
            'net' => $summaryQuery->sum('total_amount'),
            'count' => $summaryQuery->count(),
        ];
        
        return view('sales.index', compact('sales', 'parties', 'totals'));
    }

    /**
     * Show the form for creating a new sale.
     */
    public function create(): View
    {
        $parties = Party::customers()->orderBy('name')->get();
        $items = Item::where('product_type', 'finish')->where('is_active', true)->orderBy('name')->get();
        $nextBillNo = Sale::generateBillNo();
        
        return view('sales.create', compact('parties', 'items', 'nextBillNo'));
    }

    /**
     * Store a newly created sale.
     */
    public function store(Request $request)
    {
        $request->validate([
            'party_id' => 'required|exists:parties,id',
            'date' => 'required|date',
            '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 {
            // Calculate totals
            $grossAmount = 0;
            foreach ($request->items as $item) {
                if (!empty($item['item_id'])) {
                    $grossAmount += $item['quantity'] * $item['rate'];
                }
            }
            $discount = $request->discount ?? 0;
            $netAmount = $grossAmount - $discount;
            
            // Create sale
            $sale = Sale::create([
                'bill_no' => Sale::generateBillNo(),
                'date' => $request->date,
                'party_id' => $request->party_id,
                'payment_type' => $request->payment_type ?? 'credit',
                'sub_total' => $grossAmount,
                'discount_amount' => $discount,
                'total_amount' => $netAmount,
                'narration' => $request->remarks,
                'created_by' => Auth::id(),
            ]);
            
            // Create sale items and update stock
            foreach ($request->items as $item) {
                if (!empty($item['item_id'])) {
                    $amount = $item['quantity'] * $item['rate'];
                    
                    $sale->items()->create([
                        'item_id' => $item['item_id'],
                        'quantity' => $item['quantity'],
                        'rate' => $item['rate'],
                        'amount' => $amount,
                    ]);
                    
                    // Reduce stock
                    $itemModel = Item::find($item['item_id']);
                    $itemModel->reduceStock($item['quantity'], 'sale', "Sale Bill: {$sale->bill_no}");
                }
            }
            
            // Post to ledger
            $sale->postToLedger();
            
            DB::commit();
            
            if ($request->has('save_and_new')) {
                return redirect()->route('sales.create')
                    ->with('success', "Sale bill {$sale->bill_no} created successfully.");
            }
            
            return redirect()->route('sales.show', $sale)
                ->with('success', 'Sale bill created successfully.');
                
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()
                ->with('error', 'Error creating sale: ' . $e->getMessage());
        }
    }

    /**
     * Display the specified sale.
     */
    public function show(Sale $sale): View
    {
        $sale->load(['party', 'items.item', 'transactions.account', 'user']);
        return view('sales.show', compact('sale'));
    }

    /**
     * Show the form for editing the specified sale.
     */
    public function edit(Sale $sale): View
    {
        $sale->load(['items.item']);
        $parties = Party::customers()->orderBy('name')->get();
        $items = Item::where('product_type', 'finish')->where('is_active', true)->orderBy('name')->get();
        
        return view('sales.edit', compact('sale', 'parties', 'items'));
    }

    /**
     * Update the specified sale.
     */
    public function update(Request $request, Sale $sale)
    {
        $request->validate([
            'party_id' => 'required|exists:parties,id',
            'date' => 'required|date',
            '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 previous stock and ledger
            $sale->reverseStock();
            $sale->reverseLedger();
            
            // Calculate new totals
            $grossAmount = 0;
            foreach ($request->items as $item) {
                if (!empty($item['item_id'])) {
                    $grossAmount += $item['quantity'] * $item['rate'];
                }
            }
            $discount = $request->discount ?? 0;
            $netAmount = $grossAmount - $discount;
            
            // Update sale
            $sale->update([
                'date' => $request->date,
                'party_id' => $request->party_id,
                'payment_type' => $request->payment_type ?? 'credit',
                'sub_total' => $grossAmount,
                'discount_amount' => $discount,
                'total_amount' => $netAmount,
                'narration' => $request->remarks,
            ]);
            
            // Delete old items and create new ones
            $sale->items()->delete();
            
            foreach ($request->items as $item) {
                if (!empty($item['item_id'])) {
                    $amount = $item['quantity'] * $item['rate'];
                    
                    $sale->items()->create([
                        'item_id' => $item['item_id'],
                        'quantity' => $item['quantity'],
                        'rate' => $item['rate'],
                        'amount' => $amount,
                    ]);
                    
                    // Reduce stock (sale reduces stock)
                    $itemModel = Item::find($item['item_id']);
                    $itemModel->reduceStock($item['quantity'], 'sale', "Sale Bill: {$sale->bill_no}");
                }
            }
            
            // Re-post to ledger
            $sale->postToLedger();
            
            DB::commit();
            
            return redirect()->route('sales.show', $sale)
                ->with('success', 'Sale bill updated successfully.');
                
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withInput()
                ->with('error', 'Error updating sale: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified sale.
     */
    public function destroy(Sale $sale)
    {
        DB::beginTransaction();
        try {
            // Reverse stock and ledger
            $sale->reverseStock();
            $sale->reverseLedger();
            
            // Delete sale items and sale
            $sale->items()->delete();
            $sale->delete();
            
            DB::commit();
            
            return redirect()->route('sales.index')
                ->with('success', 'Sale bill deleted successfully.');
                
        } catch (\Exception $e) {
            DB::rollBack();
            return back()->with('error', 'Error deleting sale: ' . $e->getMessage());
        }
    }

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