<?php

namespace App\Http\Controllers;

use App\Models\Sale;
use App\Models\SaleItem;
use App\Models\Product;
use App\Models\HeldSale;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use App\Models\AuditLog;
use Illuminate\Support\Facades\Request as RequestFacade;

class SaleController extends Controller
{
    /**
     * Display a listing of sales.
     */
    public function index()
    {
        $this->authorize('viewAny', Sale::class);
        $salesQuery = Sale::with('user', 'saleItems.product')->latest();
        
        if (auth()->check() && auth()->user()->hasRole('Vendedor')) {
            $salesQuery->where('user_id', auth()->id());
        }

        $sales = $salesQuery->paginate(15);
        return view('sales.index', compact('sales'));
    }

    /**
     * Show the form for creating a new sale (POS).
     */
    public function create()
    {
        $clients       = \App\Models\Client::all();
        $categories    = \App\Models\Category::all();
        $quickProducts = Product::whereHas('category', fn($q) => $q->where('name', 'Varios'))
                                ->where('stock', '>', 0)
                                ->get();
        $heldSales     = HeldSale::where('user_id', auth()->id())->orderBy('created_at')->get();

        return view('sales.create', compact('clients', 'categories', 'quickProducts', 'heldSales'));
    }

    /**
     * AJAX: Paginated product search for POS catalog.
     * GET /pos/products?search=X&category=Y&page=Z
     */
    public function products(Request $request)
    {
        $query = Product::with('category')->where('stock', '>', 0);

        // Filter by category
        if ($request->filled('category') && $request->category !== '') {
            $query->where('category_id', $request->category);
        }

        // Filter by search term (name or SKU)
        if ($request->filled('search')) {
            $term = $request->search;
            $query->where(function ($q) use ($term) {
                $q->where('name', 'like', "%{$term}%")
                  ->orWhere('sku', 'like', "%{$term}%");
            });
        }

        $paginated = $query->orderBy('name')->paginate(30);

        return response()->json([
            'data'         => $paginated->map(fn($p) => [
                'id'          => $p->id,
                'name'        => $p->name,
                'sku'         => $p->sku,
                'sale_price'  => (float) $p->sale_price,
                'stock'       => (int) $p->stock,
                'min_stock'   => (int) $p->min_stock,
                'image'       => $p->image,
                'category_id' => $p->category_id,
            ]),
            'current_page' => $paginated->currentPage(),
            'last_page'    => $paginated->lastPage(),
            'total'        => $paginated->total(),
        ]);
    }

    /**
     * AJAX: Lookup a product by SKU.
     */
    public function lookup(Request $request)
    {
        $sku = trim($request->query('sku', ''));

        if (empty($sku)) {
            return response()->json(['found' => false, 'message' => 'SKU vacío.'], 400);
        }

        $product = Product::where('sku', $sku)->first();

        if (!$product) {
            return response()->json(['found' => false, 'message' => "Código '{$sku}' no encontrado en inventario."], 404);
        }

        if ($product->stock <= 0) {
            return response()->json(['found' => false, 'message' => "El producto '{$product->name}' no tiene stock disponible."], 422);
        }

        return response()->json([
            'found'   => true,
            'product' => [
                'id'         => $product->id,
                'name'       => $product->name,
                'sku'        => $product->sku,
                'sale_price' => (float) $product->sale_price,
                'stock'      => (int) $product->stock,
                'min_stock'  => (int) $product->min_stock,
                'image'      => $product->image,
            ],
        ]);
    }

    /**
     * AJAX: Get all held sales for the current user.
     */
    public function getHeldSales()
    {
        $held = HeldSale::where('user_id', auth()->id())->orderBy('created_at')->get();
        return response()->json($held);
    }

    /**
     * AJAX: Save/create a new held sale (ticket en espera).
     */
    public function storeHeldSale(Request $request)
    {
        $request->validate([
            'label'          => 'nullable|string|max:100',
            'items'          => 'required|array',
            'client_id'      => 'nullable|exists:clients,id',
            'customer_name'  => 'nullable|string|max:255',
            'payment_method' => 'nullable|string',
            'total'          => 'nullable|numeric',
        ]);

        $held = HeldSale::create([
            'user_id'        => auth()->id(),
            'label'          => $request->label ?? ('Ticket ' . (HeldSale::where('user_id', auth()->id())->count() + 1)),
            'client_id'      => $request->client_id,
            'customer_name'  => $request->customer_name,
            'payment_method' => $request->payment_method ?? 'Contado',
            'items'          => $request->items,
            'total'          => $request->total ?? 0,
        ]);

        return response()->json(['success' => true, 'held' => $held], 201);
    }

    /**
     * AJAX: Update an existing held sale.
     */
    public function updateHeldSale(Request $request, HeldSale $heldSale)
    {
        if ($heldSale->user_id !== auth()->id()) {
            return response()->json(['error' => 'No autorizado.'], 403);
        }

        $heldSale->update([
            'label'          => $request->label ?? $heldSale->label,
            'client_id'      => $request->client_id,
            'customer_name'  => $request->customer_name,
            'payment_method' => $request->payment_method ?? $heldSale->payment_method,
            'items'          => $request->items ?? $heldSale->items,
            'total'          => $request->total ?? $heldSale->total,
        ]);

        return response()->json(['success' => true, 'held' => $heldSale]);
    }

    /**
     * AJAX: Delete a held sale.
     */
    public function deleteHeldSale(HeldSale $heldSale)
    {
        if ($heldSale->user_id !== auth()->id()) {
            return response()->json(['error' => 'No autorizado.'], 403);
        }

        $heldSale->delete();
        return response()->json(['success' => true]);
    }

    /**
     * Store a newly created sale in storage.
     */
    public function store(Request $request)
    {
        $request->validate([
            'client_id'      => 'nullable|exists:clients,id',
            'customer_name'  => 'nullable|string|max:255',
            'payment_method' => 'required|in:Contado,Crédito',
            'items'          => 'required|array',
            'items.*.product_id' => 'required|exists:products,id',
            'items.*.quantity'   => 'required|integer|min:1',
            'items.*.price'      => 'required|numeric|min:0',
            'tax_rate'           => 'numeric|min:0',
            'held_sale_id'       => 'nullable|exists:held_sales,id',
        ]);

        try {
            DB::beginTransaction();

            $subtotal = 0;
            $taxRate  = $request->input('tax_rate', \App\Models\Setting::get('igv_percentage', 18) / 100);
            $lowStockAlerts = [];

            $saleItemsData = [];
            foreach ($request->items as $item) {
                $product = Product::findOrFail($item['product_id']);
                $submittedPrice = floatval($item['price']);
                $actualPrice    = (float) $product->sale_price;

                if ($product->stock < $item['quantity']) {
                    throw new \Exception("Stock insuficiente para el producto: {$product->name}");
                }

                    // Security: Log price override if submitted price != actual price
                    if (abs($submittedPrice - $actualPrice) > 0.01) {
                        AuditLog::create([
                            'user_id'        => auth()->id(),
                            'event'          => 'price_override',
                            'auditable_type' => Product::class,
                            'auditable_id'   => $product->id,
                            'old_values'     => ['price' => $actualPrice],
                            'new_values'     => ['price' => $submittedPrice],
                            'metadata'       => "Precio modificado manualmente en venta para el producto {$product->name}. Original: S/ {$actualPrice}, Cobrado: S/ {$submittedPrice}.",
                            'ip_address'     => RequestFacade::ip(),
                            'user_agent'     => RequestFacade::userAgent(),
                        ]);
                        
                        // Use Policy for price override check
                        if (!auth()->user()->can('overridePrice', Sale::class)) {
                            throw new \Exception("Seguridad: No tiene permisos para modificar precios manualmente. El producto '{$product->name}' debe cobrarse a S/ " . number_format($actualPrice, 2));
                        }
                    }

                $itemSubtotal   = $submittedPrice * $item['quantity'];
                $subtotal      += $itemSubtotal;
                $saleItemsData[] = [
                    'product_id' => $product->id,
                    'quantity'   => $item['quantity'],
                    'price'      => $submittedPrice,
                    'subtotal'   => $itemSubtotal,
                ];
            }

            $tax   = $subtotal * $taxRate;
            $total = $subtotal + $tax;

            if ($request->payment_method === 'Crédito') {
                if (!$request->client_id) {
                    throw new \Exception("Debe seleccionar un cliente registrado para ventas a crédito.");
                }
                $client          = \App\Models\Client::find($request->client_id);
                $availableCredit = $client->credit_limit - $client->credit_balance;
                if ($total > $availableCredit) {
                    throw new \Exception("El cliente no tiene suficiente crédito disponible. Crédito disponible: S/" . number_format($availableCredit, 2));
                }
                $client->increment('credit_balance', $total);
            }

            $sale = Sale::create([
                'user_id'        => auth()->id() ?? 1,
                'client_id'      => $request->client_id,
                'customer_name'  => $request->customer_name,
                'payment_method' => $request->payment_method,
                'subtotal'       => $subtotal,
                'tax'            => $tax,
                'total'          => $total,
            ]);

            foreach ($saleItemsData as $data) {
                $sale->saleItems()->create($data);
                $product = Product::find($data['product_id']);
                
                // Track stock movement
                $product->registerStockMovement(
                    $data['quantity'], 
                    'out', 
                    'Venta registrada', 
                    $sale->id, 
                    'Sale'
                );

                if ($product->stock <= $product->min_stock) {
                    $lowStockAlerts[] = $product->name;
                }
            }

            // Eliminar el ticket en espera si venía de uno
            if ($request->held_sale_id) {
                HeldSale::where('id', $request->held_sale_id)
                        ->where('user_id', auth()->id())
                        ->delete();
            }

            DB::commit();

            $message = 'Venta registrada exitosamente.';
            if (count($lowStockAlerts) > 0) {
                $message .= ' Alerta: Los productos ' . implode(', ', $lowStockAlerts) . ' han llegado a su stock mínimo límite.';
            }

            return redirect()->route('sales.index')
                ->with('success', $message)
                ->with('ticket_id', $sale->id);

        } catch (\Exception $e) {
            DB::rollBack();
            return back()->withError($e->getMessage());
        }
    }

    /**
     * Show the ticket for a sale.
     */
    public function ticket(Sale $sale)
    {
        $sale->load('user', 'client', 'saleItems.product');
        return view('sales.ticket', compact('sale'));
    }
}

