<?php

namespace App\Http\Controllers;

use App\Models\Sale;
use App\Models\Customer;
use App\Models\Product;
use App\Models\Brand;
use App\Models\Unit;
use App\Models\ProductModel;
use App\Models\Installment;
use App\Models\Payment;
use App\Models\SaleItem;
use App\Models\Setting;
use App\Http\Requests\SaleRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Schema;
use Carbon\Carbon;

class SaleController extends Controller
{
    /**
     * Get setting value from database
     */
    private function getSetting($key, $default = null)
    {
        try {
            if (class_exists('App\Models\Setting') && Schema::hasTable('settings')) {
                $setting = Setting::where('setting_key', $key)->first();
                return $setting ? $setting->setting_value : $default;
            }
        } catch (\Exception $e) {
            \Log::warning('Setting not found: ' . $key);
        }
        return $default;
    }

    /**
     * Display a listing of the resource.
     */
    public function index(Request $request)
    {
        try {
            $query = Sale::with(['customer', 'items.product', 'installments']);
            
            // Filters
            if ($request->filled('status')) {
                $query->where('status', $request->status);
            }
            if ($request->filled('sale_type')) {
                $query->where('sale_type', $request->sale_type);
            }
            if ($request->filled('payment_status')) {
                $query->where('payment_status', $request->payment_status);
            }
            if ($request->filled('customer_id')) {
                $query->where('customer_id', $request->customer_id);
            }
            
            if ($request->filled('start_date') && $request->filled('end_date')) {
                $query->whereBetween('sale_date', [$request->start_date, $request->end_date]);
            }
            
            if ($request->filled('search')) {
                $search = $request->search;
                $query->where(function($q) use ($search) {
                    $q->where('invoice_no', 'like', "%{$search}%")
                      ->orWhereHas('customer', function($q) use ($search) {
                          $q->where('name', 'like', "%{$search}%")
                            ->orWhere('phone', 'like', "%{$search}%")
                            ->orWhere('customer_code', 'like', "%{$search}%");
                      });
                });
            }
            
            $sales = $query->orderBy('created_at', 'desc')->paginate(20);
            $customers = Customer::where('status', 'active')->orderBy('name')->get(['id', 'name', 'customer_code', 'phone']);
            
            // Stats Calculation
            $stats = $this->getStatsData();
            
            // Chart data (last 7 days)
            $chartData = ['labels' => [], 'revenue' => []];
            for ($i = 6; $i >= 0; $i--) {
                $date = Carbon::now()->subDays($i);
                $chartData['labels'][] = $date->format('M d');
                $chartData['revenue'][] = Sale::whereDate('sale_date', $date->format('Y-m-d'))->sum('total_amount') ?? 0;
            }
            
            return view('sales.index', compact('sales', 'customers', 'stats', 'chartData'));
        } catch (\Exception $e) {
            \Log::error('Sale index error: ' . $e->getMessage());
            return back()->with('error', 'Unable to load sales list: ' . $e->getMessage());
        }
    }

    private function getStatsData() 
    {
        try {
            $totalSales = Sale::count();
            $totalRevenue = Sale::sum('total_amount') ?? 0;
            $cashSales = Sale::where('sale_type', 'cash')->count();
            $installmentSales = Sale::where('sale_type', 'installment')->count();
            $pendingSales = Sale::where('status', 'pending')->count();

            return [
                'total_sales' => $totalSales,
                'total_revenue' => $totalRevenue,
                'pending_sales' => $pendingSales,
                'cash_sales' => $cashSales,
                'installment_sales' => $installmentSales,
                'avg_sale_value' => $totalSales > 0 ? round($totalRevenue / $totalSales, 2) : 0,
                'cash_percentage' => $totalSales > 0 ? round(($cashSales / $totalSales * 100), 2) : 0,
                'installment_percentage' => $totalSales > 0 ? round(($installmentSales / $totalSales * 100), 2) : 0,
            ];
        } catch (\Exception $e) {
            \Log::error('Stats calculation error: ' . $e->getMessage());
            return [
                'total_sales' => 0,
                'total_revenue' => 0,
                'pending_sales' => 0,
                'cash_sales' => 0,
                'installment_sales' => 0,
                'avg_sale_value' => 0,
                'cash_percentage' => 0,
                'installment_percentage' => 0,
            ];
        }
    }

    /**
     * Show the form for creating a new resource.
     */
    public function create()
    {
        try {
            $customers = Customer::where('status', 'active')->orderBy('name')->get();
            $products = Product::where('stock_quantity', '>', 0)
                ->where('is_active', 1)
                ->orderBy('name')
                ->get();
            
            $brands = [];
            $units = [];
            $models = [];
            
            if (class_exists('App\Models\Brand') && Schema::hasTable('brands')) {
                $brands = Brand::where('status', 1)->orderBy('name')->get();
            }
            
            if (class_exists('App\Models\Unit') && Schema::hasTable('units')) {
                $units = Unit::where('status', 1)->orderBy('name')->get();
            }
            
            if (class_exists('App\Models\ProductModel') && Schema::hasTable('models')) {
                $models = ProductModel::where('status', 1)->with('brand')->orderBy('name')->get();
            }
            
            $defaultSettings = [
                'default_vat_rate' => $this->getSetting('default_vat_rate', 15),
                'default_interest_rate' => $this->getSetting('default_interest_rate', 5),
                'minimum_down_payment' => $this->getSetting('minimum_down_payment', 20),
                'max_installment_months' => $this->getSetting('max_installment_months', 36),
            ];
            
            return view('sales.create', compact('customers', 'products', 'brands', 'units', 'models', 'defaultSettings'));
        } catch (\Exception $e) {
            \Log::error('Sale create form error: ' . $e->getMessage());
            return back()->with('error', 'Unable to load form: ' . $e->getMessage());
        }
    }

    /**
     * Store a newly created resource in storage.
     */
    public function store(SaleRequest $request)
    {
        DB::beginTransaction();
        try {
            $subtotal = 0;
            $itemsData = [];
            $vatRate = floatval($request->vat_rate ?? $this->getSetting('default_vat_rate', 0));
            
            // 1. Stock Check & Subtotal Calculation
            foreach ($request->items as $item) {
                $product = Product::findOrFail($item['product_id']);
                if ($product->stock_quantity < $item['quantity']) {
                    throw new \Exception("Insufficient stock for {$product->name}. Available: {$product->stock_quantity}");
                }
                $itemTotal = $product->selling_price * $item['quantity'];
                $subtotal += $itemTotal;
                
                $itemsData[] = [
                    'product_id' => $product->id,
                    'quantity' => $item['quantity'],
                    'unit_price' => $product->selling_price,
                    'total_price' => $itemTotal,
                    'product_obj' => $product
                ];
            }

            // 2. Taxation & Discount
            $discountAmount = floatval($request->discount_amount ?? 0);
            $afterDiscount = $subtotal - $discountAmount;
            $vatAmount = $afterDiscount * ($vatRate / 100);
            $totalAmount = $afterDiscount + $vatAmount;

            // 3. Sale Type Logic
            $isInstallment = $request->sale_type === 'installment';
            $paidAmount = $isInstallment ? floatval($request->down_payment ?? 0) : $totalAmount;
            
            if ($isInstallment) {
                $minDownPercent = floatval($this->getSetting('minimum_down_payment', 20));
                $minDownAmount = $totalAmount * ($minDownPercent / 100);
                if ($paidAmount < $minDownAmount) {
                    throw new \Exception("Minimum down payment is {$minDownPercent}% ({$minDownAmount} TK). Please increase down payment.");
                }
            }

            $dueAmount = $totalAmount - $paidAmount;
            $interestRate = $isInstallment ? floatval($request->interest_rate ?? 0) : 0;
            
            // Apply interest if any
            if ($interestRate > 0 && $dueAmount > 0) {
                $interestAmount = $dueAmount * ($interestRate / 100);
                $dueAmount += $interestAmount;
                $totalAmount += $interestAmount;
            }

            // Generate invoice number
            $invoiceNo = 'INV-' . now()->format('Ymd') . '-' . str_pad(
                Sale::whereDate('created_at', today())->count() + 1, 
                4, 
                '0', 
                STR_PAD_LEFT
            );

            // 4. Create Sale
            $sale = Sale::create([
                'customer_id' => $request->customer_id,
                'user_id' => Auth::id(),
                'invoice_no' => $invoiceNo,
                'sale_type' => $request->sale_type,
                'sale_date' => $request->sale_date ?? now(),
                'total_amount' => round($totalAmount, 2),
                'discount_amount' => round($discountAmount, 2),
                'vat_amount' => round($vatAmount, 2),
                'net_amount' => round($totalAmount, 2),
                'paid_amount' => round($paidAmount, 2),
                'due_amount' => round($dueAmount, 2),
                'down_payment' => $isInstallment ? round($paidAmount, 2) : null,
                'installment_months' => $isInstallment ? $request->installment_months : null,
                'monthly_installment' => $isInstallment && $dueAmount > 0 ? round($dueAmount / $request->installment_months, 2) : null,
                'interest_rate' => $interestRate,
                'status' => $isInstallment ? 'pending' : 'completed',
                'payment_status' => $dueAmount > 0 ? 'partial' : 'paid',
                'notes' => $request->notes,
            ]);

            // 5. Sale Items & Stock Update
            $itemCount = count($itemsData);
            $discountPerItem = $itemCount > 0 ? $discountAmount / $itemCount : 0;
            
            foreach ($itemsData as $data) {
                $itemTotal = $data['total_price'];
                $itemDiscount = round($discountPerItem, 2);
                $itemAfterDiscount = $itemTotal - $itemDiscount;
                $itemVatAmount = $itemAfterDiscount * ($vatRate / 100);
                
                SaleItem::create([
                    'sale_id' => $sale->id,
                    'product_id' => $data['product_id'],
                    'quantity' => $data['quantity'],
                    'unit_price' => $data['unit_price'],
                    'discount' => $itemDiscount,
                    'vat_rate' => $vatRate,
                    'vat_amount' => round($itemVatAmount, 2),
                    'total_price' => round($itemAfterDiscount + $itemVatAmount, 2),
                ]);
                
                // Update stock
                $data['product_obj']->decrement('stock_quantity', $data['quantity']);
            }

            // 6. Installments Generation
            if ($isInstallment && $dueAmount > 0 && $request->installment_months > 0) {
                $months = intval($request->installment_months);
                $instAmount = round($dueAmount / $months, 2);
                $totalInstAmount = 0;
                
                for ($i = 1; $i <= $months; $i++) {
                    // Last installment adjustment to fix rounding issues
                    if ($i == $months) {
                        $instAmount = $dueAmount - $totalInstAmount;
                    }
                    
                    Installment::create([
                        'sale_id' => $sale->id,
                        'installment_no' => $i,
                        'amount' => round($instAmount, 2),
                        'paid_amount' => 0,
                        'due_amount' => round($instAmount, 2),
                        'due_date' => Carbon::parse($sale->sale_date)->addMonths($i),
                        'status' => 'pending',
                    ]);
                    
                    $totalInstAmount += $instAmount;
                }
                
                // Update customer outstanding balance
                Customer::where('id', $request->customer_id)->increment('outstanding_balance', $dueAmount);
            }

            // 7. Payment Record
            if ($paidAmount > 0) {
                Payment::create([
                    'sale_id' => $sale->id,
                    'customer_id' => $request->customer_id,
                    'installment_id' => null,
                    'payment_no' => $this->generatePaymentNo(),
                    'payment_type' => $isInstallment ? 'down_payment' : 'full_payment',
                    'amount' => round($paidAmount, 2),
                    'payment_method' => $request->payment_method ?? 'cash',
                    'payment_date' => $request->sale_date ?? now(),
                    'received_by' => Auth::id(),
                    'notes' => $isInstallment ? 'Down payment for installment sale' : 'Full payment',
                ]);
            }

            DB::commit();
            return redirect()->route('sales.show', $sale)->with('success', 'Sale created successfully! Invoice: ' . $sale->invoice_no);
            
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::error('Sale creation error: ' . $e->getMessage());
            return back()->withInput()->with('error', 'Failed to create sale: ' . $e->getMessage());
        }
    }

    /**
     * Display the specified resource.
     */
    public function show(Sale $sale)
    {
        try {
            // Load all necessary relationships
            $sale->load([
                'customer', 
                'user', 
                'items' => function($query) {
                    $query->with('product');
                },
                'installments',
                'payments' => function($query) {
                    $query->with('receivedBy');
                }
            ]);
            
            // Ensure items is a collection
            if (!$sale->items) {
                $sale->items = collect();
            }
            
            // Ensure installments is a collection
            if (!$sale->installments) {
                $sale->installments = collect();
            }
            
            // Ensure payments is a collection
            if (!$sale->payments) {
                $sale->payments = collect();
            }
            
            $paymentSummary = [
                'total_paid' => $sale->payments->sum('amount'),
                'remaining_due' => $sale->due_amount,
                'installments_paid' => $sale->installments->where('status', 'paid')->count(),
                'installments_pending' => $sale->installments->where('status', 'pending')->count(),
            ];
            
            return view('sales.show', compact('sale', 'paymentSummary'));
            
        } catch (\Exception $e) {
            \Log::error('Sale show error: ' . $e->getMessage());
            return redirect()->route('sales.index')
                ->with('error', 'Unable to load sale details: ' . $e->getMessage());
        }
    }

    /**
     * Show the form for editing the specified resource.
     */
    public function edit(Sale $sale)
    {
        try {
            $sale->load(['customer', 'items.product', 'installments', 'payments']);
            $customers = Customer::where('status', 'active')->orderBy('name')->get();
            $products = Product::where('is_active', 1)->orderBy('name')->get();
            
            return view('sales.edit', compact('sale', 'customers', 'products'));
        } catch (\Exception $e) {
            \Log::error('Sale edit error: ' . $e->getMessage());
            return redirect()->route('sales.index')
                ->with('error', 'Unable to load sale for editing: ' . $e->getMessage());
        }
    }

    /**
     * Update the specified resource in storage.
     */
    public function update(Request $request, Sale $sale)
    {
        DB::beginTransaction();
        try {
            // Update logic here
            $sale->update($request->only([
                'customer_id',
                'sale_date',
                'notes',
                'status',
                'payment_status',
                'delivery_status'
            ]));
            
            DB::commit();
            return redirect()->route('sales.show', $sale)
                ->with('success', 'Sale updated successfully!');
                
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::error('Sale update error: ' . $e->getMessage());
            return back()->with('error', 'Failed to update sale: ' . $e->getMessage());
        }
    }

    /**
     * Remove the specified resource from storage.
     */
    public function destroy(Sale $sale)
    {
        DB::beginTransaction();
        try {
            // Check if sale can be deleted
            if ($sale->status === 'completed' && $sale->payment_status === 'paid') {
                throw new \Exception('Cannot delete a completed and fully paid sale.');
            }
            
            // Restore stock
            foreach ($sale->items as $item) {
                Product::where('id', $item->product_id)->increment('stock_quantity', $item->quantity);
            }
            
            // Delete related records
            $sale->items()->delete();
            $sale->installments()->delete();
            $sale->payments()->delete();
            $sale->delete();
            
            DB::commit();
            return redirect()->route('sales.index')
                ->with('success', 'Sale deleted successfully!');
                
        } catch (\Exception $e) {
            DB::rollBack();
            \Log::error('Sale deletion error: ' . $e->getMessage());
            return back()->with('error', 'Failed to delete sale: ' . $e->getMessage());
        }
    }

    /**
     * Print invoice
     */
    public function printInvoice(Sale $sale)
    {
        try {
            $sale->load([
                'customer', 
                'items.product', 
                'user',
                'installments',
                'payments'
            ]);
            
            return view('sales.invoice', compact('sale'));
        } catch (\Exception $e) {
            \Log::error('Invoice print error: ' . $e->getMessage());
            return redirect()->route('sales.show', $sale)
                ->with('error', 'Unable to print invoice: ' . $e->getMessage());
        }
    }

    /**
     * Generate payment number
     */
    private function generatePaymentNo()
    {
        $count = Payment::whereDate('created_at', today())->count();
        return 'PAY-' . date('Ymd') . '-' . str_pad($count + 1, 4, '0', STR_PAD_LEFT);
    }
    
    /**
     * Get product details for AJAX
     */
    public function getProductDetails($id)
    {
        try {
            $product = Product::with(['category', 'brand'])->findOrFail($id);
            return response()->json([
                'success' => true,
                'product' => $product,
                'price' => $product->selling_price,
                'stock' => $product->stock_quantity,
                'name' => $product->name,
                'code' => $product->code
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Product not found'
            ], 404);
        }
    }
    
    /**
     * Get customer details for AJAX
     */
    public function getCustomerDetails($id)
    {
        try {
            $customer = Customer::findOrFail($id);
            return response()->json([
                'success' => true,
                'customer' => $customer,
                'outstanding_balance' => $customer->outstanding_balance,
                'credit_limit' => $customer->credit_limit,
                'customer_type' => $customer->customer_type
            ]);
        } catch (\Exception $e) {
            return response()->json([
                'success' => false,
                'message' => 'Customer not found'
            ], 404);
        }
    }
    
    /**
     * Get sales statistics for dashboard
     */
    public function statistics(Request $request)
    {
        try {
            $startDate = $request->get('start_date', Carbon::now()->startOfMonth());
            $endDate = $request->get('end_date', Carbon::now()->endOfMonth());
            
            $stats = [
                'total_sales' => Sale::whereBetween('sale_date', [$startDate, $endDate])->count(),
                'total_revenue' => Sale::whereBetween('sale_date', [$startDate, $endDate])->sum('total_amount'),
                'cash_sales' => Sale::where('sale_type', 'cash')->whereBetween('sale_date', [$startDate, $endDate])->count(),
                'installment_sales' => Sale::where('sale_type', 'installment')->whereBetween('sale_date', [$startDate, $endDate])->count(),
                'avg_sale_value' => Sale::whereBetween('sale_date', [$startDate, $endDate])->avg('total_amount') ?? 0,
            ];
            
            return response()->json($stats);
        } catch (\Exception $e) {
            return response()->json(['error' => $e->getMessage()], 500);
        }
    }
}