<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

use App\Models\BuyReceipt;
use App\Models\CostBuyReceipt;
use App\Models\Transaction;
use App\Models\KardexDeposit;
use Illuminate\Support\Facades\DB;

class BuyReceiptController extends Controller
{
    public function index(Request $request)
    {
        $perPage = $request->get('per_page', 10);
        $search = $request->get('search', '');
        
        // Filtros
        $fechaInicio = $request->get('fecha_inicio', '');
        $fechaFin = $request->get('fecha_fin', '');
        $idSupplier = $request->get('id_supplier', '');
        $tipo = $request->get('tipo', '');
        $paymentType = $request->get('payment_type', '');
        
        // Ordenamiento
        $sortField = $request->get('sort_field', 'id');
        $sortDirection = $request->get('sort_direction', 'desc');

        $query = BuyReceipt::with(['transaction', 'supplier']);

        // Búsqueda por número
        if ($search) {
            $query->where('number', 'like', "%{$search}%");
        }

        // Filtro por rango de fechas
        if ($fechaInicio) {
            $query->whereHas('transaction', function ($q) use ($fechaInicio) {
                $q->where('date', '>=', $fechaInicio);
            });
        }
        if ($fechaFin) {
            $query->whereHas('transaction', function ($q) use ($fechaFin) {
                $q->where('date', '<=', $fechaFin . ' 23:59:59');
            });
        }

        // Filtro por proveedor
        if ($idSupplier) {
            $query->where('id_supplier', $idSupplier);
        }

        // Filtro por tipo
        if ($tipo) {
            $query->where('type', $tipo);
        }

        // Filtro por método de pago
        if ($paymentType) {
            $query->where('payment_type', $paymentType);
        }

        // Ordenamiento
        if ($sortField === 'supplier.name') {
            $query->join('suppliers', 'buy_receipts.id_supplier', '=', 'suppliers.id')
                  ->orderBy('suppliers.razon_social', $sortDirection)
                  ->select('buy_receipts.*');
        } elseif ($sortField === 'date') {
            $query->join('transactions', 'buy_receipts.id_transaction', '=', 'transactions.id')
                  ->orderBy('transactions.date', $sortDirection)
                  ->select('buy_receipts.*');
        } else {
            $query->orderBy($sortField, $sortDirection);
        }

        $buyReceipts = $query->paginate($perPage);

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

    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'type' => 'required|string|max:255',
            'serie' => 'required|string|max:255',
            'number' => 'required|string|max:255',
            'id_supplier' => 'required|integer|exists:suppliers,id',
            'observation' => 'nullable|string|max:255',
            'payment_type' => 'required|string|max:255',
            'date' => 'required|date',
            'total' => 'required|numeric',
            'igv' => 'required|numeric',
            'subtotal' => 'required|numeric',
            'costs' => 'nullable|array',
            'costs.*.id_product' => 'nullable|integer',
            'costs.*.id_unit' => 'nullable|integer',
            'costs.*.quantity' => 'required|numeric',
            'costs.*.price_buy' => 'required|numeric',
            'costs.*.total' => 'required|numeric',
            'costs.*.equivale' => 'nullable|numeric',
        ]);

        DB::beginTransaction();
        try {
            // Crear transacción
            $transaction = Transaction::create([
                'motion' => 'BuyProducts',
                'type' => 'egreso',
                'date' => $validatedData['date'] . ' ' . now()->format('H:i:s'),
                'total' => $validatedData['total'],
                'igv' => $validatedData['igv'],
                'subtotal' => $validatedData['subtotal'],
            ]);

            // Crear buy_receipt
            $buyReceipt = BuyReceipt::create([
                'type' => $validatedData['type'],
                'serie' => $validatedData['serie'],
                'number' => $validatedData['number'],
                'id_supplier' => $validatedData['id_supplier'],
                'observation' => $validatedData['observation'] ?? null,
                'payment_type' => $validatedData['payment_type'],
                'id_transaction' => $transaction->id,
                'id_user' => auth()->user()->id,
                'id_store' => auth()->user()->id_store,
            ]);

            // Guardar costos si existen
            if (!empty($validatedData['costs'])) {
                foreach ($validatedData['costs'] as $cost) {
                    CostBuyReceipt::create([
                        'id_product' => $cost['id_product'] ?? null,
                        'id_unit' => $cost['id_unit'] ?? null,
                        'quantity' => $cost['quantity'],
                        'price_buy' => $cost['price_buy'],
                        'total' => $cost['total'],
                        'id_buy_receipt' => $buyReceipt->id,
                        'equivale' => $cost['equivale'] ?? null,
                    ]);

                    // Actualizar stock del producto
                    if (!empty($cost['id_product'])) {
                        $product = \App\Models\Input::find($cost['id_product']);
                        if ($product) {
                            // Stock = cantidad * equivale (ej: 10 cajas × 20kg = 200kg)
                            $stockAgregar = $cost['quantity'] * ($cost['equivale'] ?? 1);
                            $stockAnterior = $product->stock ?? 0;
                            $stockActual = $stockAnterior + $stockAgregar;
                            
                            $product->stock = $stockActual;
                            $product->save();

                            // Registrar movimiento en kardex de almacén
                            $this->registrarKardexDeposit(
                                $cost['id_product'],
                                'entrada',
                                'buy_receipt',
                                $buyReceipt->id,
                                $stockAgregar,
                                $stockAnterior,
                                $stockActual,
                                $validatedData['date']
                            );

                            // Crear o actualizar cost_input
                            $this->crearOActualizarCostInput(
                                $cost['id_product'],
                                $cost['id_unit'] ?? null,
                                $cost['quantity'],
                                $cost['price_buy'],
                                $cost['equivale'] ?? null
                            );
                        }
                    }
                }
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Compra registrada exitosamente',
                'data' => $buyReceipt
            ], 201);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Error al registrar la compra',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function update(Request $request, $id)
    {
        $buyReceipt = BuyReceipt::findOrFail($id);

        $validatedData = $request->validate([
            'type' => 'required|string|max:255',
            'serie' => 'required|string|max:255',
            'number' => 'required|string|max:255',
            'id_supplier' => 'required|integer|exists:suppliers,id',
            'observation' => 'nullable|string|max:255',
            'payment_type' => 'required|string|max:255',
            'date' => 'required|date',
            'total' => 'required|numeric',
            'igv' => 'required|numeric',
            'subtotal' => 'required|numeric',
            'costs' => 'nullable|array',
            'costs.*.id' => 'nullable|exists:cost_buy_receipt,id',
            'costs.*.id_product' => 'nullable|integer',
            'costs.*.id_unit' => 'nullable|integer',
            'costs.*.quantity' => 'required|numeric',
            'costs.*.price_buy' => 'required|numeric',
            'costs.*.total' => 'required|numeric',
            'costs.*.equivale' => 'nullable|numeric',
        ]);

        DB::beginTransaction();
        try {
            $buyReceipt->update($validatedData);

            // Revertir stock de los costos antiguos
            $oldCosts = CostBuyReceipt::where('id_buy_receipt', $buyReceipt->id)->get();
            foreach ($oldCosts as $oldCost) {
                if (!empty($oldCost->id_product)) {
                    $product = \App\Models\Input::find($oldCost->id_product);
                    if ($product) {
                        $product->stock = ($product->stock ?? 0) - $oldCost->quantity;
                        $product->save();
                    }
                }
            }

            // Sincronizar costos (elimina todos y vuelve a crear)
            if (isset($validatedData['costs'])) {
                CostBuyReceipt::where('id_buy_receipt', $buyReceipt->id)->delete();
                foreach ($validatedData['costs'] as $cost) {
                    CostBuyReceipt::create([
                        'id_product' => $cost['id_product'] ?? null,
                        'id_unit' => $cost['id_unit'] ?? null,
                        'quantity' => $cost['quantity'],
                        'price_buy' => $cost['price_buy'],
                        'total' => $cost['total'],
                        'id_buy_receipt' => $buyReceipt->id,
                        'equivale' => $cost['equivale'] ?? null,
                    ]);

                    // Actualizar stock del producto con los nuevos valores
                    if (!empty($cost['id_product'])) {
                        $product = \App\Models\Input::find($cost['id_product']);
                        if ($product) {
                            // Stock = cantidad * equivale (ej: 10 cajas × 20kg = 200kg)
                            $stockAgregar = $cost['quantity'] * ($cost['equivale'] ?? 1);
                            $stockAnterior = $product->stock ?? 0;
                            $stockActual = $stockAnterior + $stockAgregar;
                            
                            $product->stock = $stockActual;
                            $product->save();

                            // Registrar movimiento en kardex de almacén
                            $this->registrarKardexDeposit(
                                $cost['id_product'],
                                'entrada',
                                'buy_receipt',
                                $buyReceipt->id,
                                $stockAgregar,
                                $stockAnterior,
                                $stockActual,
                                $validatedData['date']
                            );

                            // Crear o actualizar cost_input
                            $this->crearOActualizarCostInput(
                                $cost['id_product'],
                                $cost['id_unit'] ?? null,
                                $cost['quantity'],
                                $cost['price_buy'],
                                $cost['equivale'] ?? null
                            );
                        }
                    }
                }
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Compra actualizada exitosamente',
            ]);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Error al actualizar la compra',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    public function destroy($id)
    {
        $buyReceipt = BuyReceipt::findOrFail($id);
        
        // Revertir stock antes de eliminar y registrar en kardex
        $costs = CostBuyReceipt::where('id_buy_receipt', $buyReceipt->id)->get();
        foreach ($costs as $cost) {
            if (!empty($cost->id_product)) {
                $product = \App\Models\Input::find($cost->id_product);
                if ($product) {
                    // Revertir stock = cantidad * equivale
                    $stockRevertir = $cost->quantity * ($cost->equivale ?? 1);
                    $stockAnterior = $product->stock ?? 0;
                    $stockActual = $stockAnterior - $stockRevertir;
                    
                    $product->stock = $stockActual;
                    $product->save();

                    // Registrar salida en kardex por eliminación
                    $this->registrarKardexDeposit(
                        $cost->id_product,
                        'salida',
                        'buy_receipt_delete',
                        $buyReceipt->id,
                        $stockRevertir,
                        $stockAnterior,
                        $stockActual,
                        now()
                    );
                }
            }
        }
        
        CostBuyReceipt::where('id_buy_receipt', $buyReceipt->id)->delete();
        $buyReceipt->delete();

        return response()->json([
            'success' => true,
            'message' => 'Compra eliminada exitosamente'
        ]);
    }

    public function show($id)
    {
        $buyReceipt = BuyReceipt::with(['costBuyReceipts', 'transaction', 'supplier'])->findOrFail($id);

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

    public function selectData()
    {
        $suppliers = \App\Models\Supplier::select('id', 'razon_social as name')->get();
        $products = \App\Models\Input::with(['unit:id,name_es'])
            ->select('id', 'name', 'stock', 'id_unit')
            ->get();
        $units = \App\Models\Unit::select('id', 'name_es as name')->get();

        return response()->json([
            'success' => true,
            'suppliers' => $suppliers,
            'products' => $products,
            'units' => $units,
        ]);
    }

    /**
     * Crea o actualiza el cost_input de un producto con una unidad específica
     */
    private function crearOActualizarCostInput($idProduct, $idUnit, $cantidadComprada, $precioCompra, $equivale = null)
    {
        // Calcular precio de venta (20% de ganancia)
        $precioVenta = $precioCompra * 1.20;

        // Buscar si ya existe un cost_input para este producto con esta unidad
        $costInput = \App\Models\CostInput::where('id_input', $idProduct)
            ->where('id_unit', $idUnit)
            ->first();

        if ($costInput) {
            // Si existe, actualizar los valores
            $costInput->update([
                'cantidad' => $equivale ?? $cantidadComprada, // Cuántas unidades trae (ej: 50 por paquete)
                'precio_compra' => $precioCompra,
                'precio_venta' => $precioVenta,
            ]);
        } else {
            // Si no existe, crear uno nuevo
            \App\Models\CostInput::create([
                'id_input' => $idProduct,
                'id_unit' => $idUnit,
                'cantidad' => $equivale ?? 1, // Cuántas unidades trae (por defecto 1)
                'precio_compra' => $precioCompra,
                'precio_venta' => $precioVenta,
            ]);
        }
    }

    /**
     * Registra un movimiento en el kardex de almacén (deposit)
     */
    private function registrarKardexDeposit($idProduct, $tipoMovimiento, $documentoTipo, $documentoId, $cantidad, $stockAnterior, $stockActual, $fecha)
    {
        // Obtener el depósito del producto (asumiendo que cada producto tiene un depósito asignado)
        $product = \App\Models\Input::find($idProduct);
        if (!$product) return;

        // Si el producto tiene deposit_inputs, usar el primer depósito encontrado
        $depositInput = \App\Models\DepositInput::where('id_input', $idProduct)->first();
        $idDeposit = $depositInput ? $depositInput->id_deposit : 1; // Por defecto depósito 1

        KardexDeposit::create([
            'id_deposit' => $idDeposit,
            'id_input' => $idProduct,
            'tipo_movimiento' => $tipoMovimiento,
            'documento_tipo' => $documentoTipo,
            'documento_id' => $documentoId,
            'cantidad' => $cantidad,
            'stock_anterior' => $stockAnterior,
            'stock_actual' => $stockActual,
            'fecha' => $fecha,
            'observacion' => ucfirst($tipoMovimiento) . ' por ' . $documentoTipo,
        ]);
    }
}
