<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Models\SalesGuide;
use App\Models\CostSalesGuide;
use App\Models\KardexDeposit;
use App\Models\KardexStore;
use Illuminate\Support\Facades\DB;
use App\Models\Store;
use App\Models\Deposit;
use App\Models\Customer;
use App\Models\Carrier;
use App\Models\Input;
use App\Models\Unit;
use App\Models\Transaction;
use App\Models\Requirement;

class SalesGuideController extends Controller
{
    // Listado paginado
    public function index(Request $request)
    {
        $perPage = $request->get('per_page', 10);
        $search = $request->get('search', '');
        $idRequirement = $request->get('id_requirement');
        $fechaInicio = $request->get('fecha_inicio');
        $fechaFin = $request->get('fecha_fin');
        $idStore = $request->get('id_store');
        $idCustomer = $request->get('id_customer');
        $idCarrier = $request->get('id_carrier');
        $sortField = $request->get('sort_field', 'id');
        $sortDirection = $request->get('sort_direction', 'desc');

        $query = SalesGuide::with(['store', 'deposit', 'customer', 'carrier', 'requirement']);

        if ($search) {
            $query->where('serie', 'like', "%{$search}%")
                  ->orWhere('number', 'like', "%{$search}%");
        }

        if ($idRequirement) {
            $query->where('id_requirement', $idRequirement);
        }
        if ($idStore) {
            $query->where('id_store', $idStore);
        }
        if ($idCustomer) {
            $query->where('id_customer', $idCustomer);
        }
        if ($idCarrier) {
            $query->where('id_carrier', $idCarrier);
        }

        // Filtro de fechas
        if ($fechaInicio && $fechaFin) {
            $query->whereBetween('fecha_emision', [$fechaInicio, $fechaFin]);
        } elseif ($fechaInicio) {
            $query->where('fecha_emision', '>=', $fechaInicio);
        } elseif ($fechaFin) {
            $query->where('fecha_emision', '<=', $fechaFin);
        }

        // Ordenamiento con soporte para relaciones
        $allowedFields = ['id', 'serie', 'number', 'fecha_emision', 'fecha_traslado', 'motivo'];
        if (in_array($sortField, $allowedFields)) {
            $query->orderBy($sortField, $sortDirection);
        } elseif ($sortField === 'store.name') {
            $query->join('stores', 'sales_guide.id_store', '=', 'stores.id')
                  ->orderBy('stores.name', $sortDirection)
                  ->select('sales_guide.*');
        } elseif ($sortField === 'customer.name') {
            $query->join('customers', 'sales_guide.id_customer', '=', 'customers.id')
                  ->orderBy('customers.razon_social', $sortDirection)
                  ->select('sales_guide.*');
        } elseif ($sortField === 'carrier.name') {
            $query->leftJoin('carriers', 'sales_guide.id_carrier', '=', 'carriers.id')
                  ->orderBy('carriers.name', $sortDirection)
                  ->select('sales_guide.*');
        } elseif ($sortField === 'deposit.name') {
            $query->leftJoin('deposits', 'sales_guide.id_deposit', '=', 'deposits.id')
                  ->orderBy('deposits.name', $sortDirection)
                  ->select('sales_guide.*');
        } else {
            $query->orderBy('id', 'desc');
        }

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

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

    // Obtener guía por id_requirement
    public function getByRequirement($idRequirement)
    {
        $guide = SalesGuide::with(['store', 'deposit', 'customer', 'carrier', 'requirement', 'costSalesGuides.input.unit', 'costSalesGuides.unit'])
            ->where('id_requirement', $idRequirement)
            ->first();

        if (!$guide) {
            return response()->json([
                'success' => false,
                'message' => 'No se encontró una guía de venta para este requerimiento'
            ], 404);
        }

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

    // Crear nueva guía de venta
    public function store(Request $request)
    {
        $validatedData = $request->validate([
            'serie'         => 'required|string|max:255',
            'number'        => 'required|integer|unique:sales_guide,number',
            'fecha_emision' => 'nullable|string|max:255',
            'fecha_traslado'=> 'nullable|string|max:255',
            'id_deposit'    => 'nullable|exists:deposits,id',
            'id_store'      => 'required|exists:stores,id',
            'motivo'        => 'nullable|string|max:255',
            'id_customer'   => 'required|exists:customers,id',
            'id_carrier'    => 'nullable|exists:carriers,id',
            'id_requirement'=> 'nullable|exists:requirements,id',
            'costs'         => 'nullable|array',
            'costs.*.cantidad'             => 'required|string|max:255',
            'costs.*.id_input'             => 'required|integer|exists:inputs,id',
            'costs.*.id_unit'              => 'nullable|integer|exists:unit_measures,id',
            'costs.*.equivale'             => 'nullable|numeric',
            'costs.*.unit_name'            => 'nullable|string|max:255',
            'costs.*.precio_venta'         => 'nullable|numeric',
            'costs.*.total'                => 'nullable|numeric',
            'costs.*.cantidad_presentacion'=> 'nullable|numeric',
        ], [
            'serie.required' => 'La serie es obligatoria.',
            'number.required' => 'El número es obligatorio.',
            'number.unique' => 'El número ya está registrado.',
            'id_store.required' => 'La tienda es obligatoria.',
            'id_customer.required' => 'El cliente es obligatorio.',
            'costs.*.cantidad.required' => 'La cantidad es obligatoria.',
            'costs.*.id_input.required' => 'El insumo es obligatorio.',
        ]);

        DB::beginTransaction();
        try {
            // Calcular totales desde los costos
            $totalGeneral = 0;
            if (!empty($validatedData['costs'])) {
                foreach ($validatedData['costs'] as $cost) {
                    $totalGeneral += floatval($cost['total'] ?? 0);
                }
            }
            
            // Calcular subtotal e IGV (18%)
            $subtotal = $totalGeneral / 1.18;
            $igv = $totalGeneral - $subtotal;

            // Crear transacción
            $fechaEmision = $validatedData['fecha_emision'] ?? date('Y-m-d');
            $transaction = Transaction::create([
                'motion' => 'SaleGuides',
                'type' => 'ingreso',
                'date' => $fechaEmision . ' ' . now()->format('H:i:s'),
                'total' => $totalGeneral,
                'igv' => $igv,
                'subtotal' => $subtotal,
            ]);

            // Crear guía de venta
            $guide = SalesGuide::create([
                'serie'          => $validatedData['serie'],
                'number'         => $validatedData['number'],
                'fecha_emision'  => $fechaEmision,
                'fecha_traslado' => $validatedData['fecha_traslado'] ?? null,
                'id_deposit'     => $validatedData['id_deposit'] ?? null,
                'id_store'       => $validatedData['id_store'],
                'motivo'         => $validatedData['motivo'] ?? null,
                'id_customer'    => $validatedData['id_customer'],
                'id_carrier'     => $validatedData['id_carrier'] ?? null,
                'id_requirement' => $validatedData['id_requirement'] ?? null,
                'id_transaction' => $transaction->id,
                'id_user'        => auth()->user()->id,
            ]);

            // Guardar costos si existen
            if (!empty($validatedData['costs'])) {
                foreach ($validatedData['costs'] as $cost) {
                    $guide->costSalesGuides()->create([
                        'cantidad'               => $cost['cantidad'],
                        'id_input'               => $cost['id_input'],
                        'id_unit'                => $cost['id_unit'] ?? null,
                        'equivale'               => $cost['equivale'] ?? null,
                        'unit_name'              => $cost['unit_name'] ?? null,
                        'precio_venta'           => $cost['precio_venta'] ?? null,
                        'total'                  => $cost['total'] ?? null,
                        'cantidad_presentacion'  => $cost['cantidad_presentacion'] ?? null,
                        'id_sales_guide'         => $guide->id,
                    ]);

                    // Restar stock del input usando equivale
                    if ($cost['id_input']) {
                        $input = Input::find($cost['id_input']);
                        if ($input) {
                            $cantidadARestar = floatval($cost['cantidad']);
                            $stockAnterior = $input->stock ?? 0;
                            $stockActual = $stockAnterior - $cantidadARestar;
                            
                            $input->stock = $stockActual;
                            $input->save();

                            // Registrar salida del almacén en kardex
                            $this->registrarKardexDeposit(
                                $cost['id_input'],
                                'salida',
                                'sales_guide',
                                $guide->id,
                                $cantidadARestar,
                                $stockAnterior,
                                $stockActual,
                                $fechaEmision
                            );

                            // Registrar entrada a la tienda en kardex
                            $this->registrarKardexStore(
                                $validatedData['id_store'],
                                $cost['id_input'],
                                'entrada',
                                'sales_guide',
                                $guide->id,
                                $cantidadARestar,
                                $fechaEmision
                            );
                        }
                    }
                }
            }

            //actualizr el requerimiento como atendido
            if (!empty($validatedData['id_requirement'])) {
                $requirement = Requirement::find($validatedData['id_requirement']);
                if ($requirement) {
                    $requirement->status = 'Aprobado';
                    $requirement->save();
                }
            }

            DB::commit();

            return response()->json([
                'success' => true,
                'message' => 'Guía de venta creada exitosamente',
                'data' => $guide->load(['costSalesGuides.input.unit', 'store', 'deposit', 'customer', 'carrier', 'transaction'])
            ], 201);
        } catch (\Exception $e) {
            DB::rollBack();
            return response()->json([
                'success' => false,
                'message' => 'Error al crear la guía de venta',
                'error' => $e->getMessage()
            ], 500);
        }
    }

    // Actualizar guía de venta
    public function update(Request $request, $id)
    {
        $guide = SalesGuide::findOrFail($id);

        $validatedData = $request->validate([
            'serie'         => 'required|string|max:255',
            'number'        => 'required|integer|unique:sales_guide,number,' . $guide->id,
            'fecha_emision' => 'nullable|string|max:255',
            'fecha_traslado'=> 'nullable|string|max:255',
            'id_deposit'    => 'nullable|exists:deposits,id',
            'id_store'      => 'required|exists:stores,id',
            'motivo'        => 'nullable|string|max:255',
            'id_customer'   => 'required|exists:customers,id',
            'id_carrier'    => 'nullable|exists:carriers,id',
            'id_requirement'=> 'nullable|exists:requirements,id',
            'costs'         => 'nullable|array',
            'costs.*.id'                    => 'nullable|exists:cost_sales_guide,id',
            'costs.*.cantidad'              => 'required|string|max:255',
            'costs.*.id_input'              => 'required|integer|exists:inputs,id',
            'costs.*.id_unit'               => 'nullable|integer|exists:unit_measures,id',
            'costs.*.equivale'              => 'nullable|numeric',
            'costs.*.unit_name'             => 'nullable|string|max:255',
            'costs.*.precio_venta'          => 'nullable|numeric',
            'costs.*.total'                 => 'nullable|numeric',
            'costs.*.cantidad_presentacion' => 'nullable|numeric',
        ], [
            'serie.required' => 'La serie es obligatoria.',
            'number.required' => 'El número es obligatorio.',
            'number.unique' => 'El número ya está registrado.',
            'id_store.required' => 'La tienda es obligatoria.',
            'id_customer.required' => 'El cliente es obligatorio.',
            'costs.*.cantidad.required' => 'La cantidad es obligatoria.',
            'costs.*.id_input.required' => 'El insumo es obligatorio.',
        ]);

        DB::beginTransaction();
        try {
            // Calcular totales desde los costos
            $totalGeneral = 0;
            if (!empty($validatedData['costs'])) {
                foreach ($validatedData['costs'] as $cost) {
                    $totalGeneral += floatval($cost['total'] ?? 0);
                }
            }
            
            // Calcular subtotal e IGV (18%)
            $subtotal = $totalGeneral / 1.18;
            $igv = $totalGeneral - $subtotal;

            // Actualizar o crear transacción
            $fechaEmision = $validatedData['fecha_emision'] ?? date('Y-m-d');
            if ($guide->id_transaction) {
                $guide->transaction->update([
                    'date' => $fechaEmision . ' ' . now()->format('H:i:s'),
                    'total' => $totalGeneral,
                    'igv' => $igv,
                    'subtotal' => $subtotal,
                ]);
            } else {
                $transaction = Transaction::create([
                    'motion' => 'SaleProducts',
                    'type' => 'ingreso',
                    'date' => $fechaEmision . ' ' . now()->format('H:i:s'),
                    'total' => $totalGeneral,
                    'igv' => $igv,
                    'subtotal' => $subtotal,
                ]);
                $validatedData['id_transaction'] = $transaction->id;
            }

            // Actualizar guía de venta
            $guide->update($validatedData);

            // Devolver stock de los costos antiguos
            $oldCosts = CostSalesGuide::where('id_sales_guide', $guide->id)->get();
            foreach ($oldCosts as $oldCost) {
                if (!empty($oldCost->id_input) && isset($oldCost->equivale) && $oldCost->equivale > 0) {
                    $input = Input::find($oldCost->id_input);
                    if ($input) {
                        $cantidadADevolver = floatval($oldCost->equivale);
                        $input->stock = ($input->stock ?? 0) + $cantidadADevolver;
                        $input->save();
                    }
                }
            }

            // Sincronizar costos (elimina todos y vuelve a crear)
            if (isset($validatedData['costs'])) {
                $guide->costSalesGuides()->delete();
                foreach ($validatedData['costs'] as $cost) {
                    $guide->costSalesGuides()->create([
                        'cantidad'               => $cost['cantidad'],
                        'id_input'               => $cost['id_input'],
                        'id_unit'                => $cost['id_unit'] ?? null,
                        'equivale'               => $cost['equivale'] ?? null,
                        'unit_name'              => $cost['unit_name'] ?? null,
                        'precio_venta'           => $cost['precio_venta'] ?? null,
                        'total'                  => $cost['total'] ?? null,
                        'cantidad_presentacion'  => $cost['cantidad_presentacion'] ?? null,
                        'id_sales_guide'         => $guide->id,
                    ]);

                    // Restar stock del input con los nuevos valores usando equivale
                    if (!empty($cost['id_input'])) {
                        $input = Input::find($cost['id_input']);
                        if ($input) {
                            $cantidadARestar = floatval($cost['cantidad']);
                            $stockAnterior = $input->stock ?? 0;
                            $stockActual = $stockAnterior - $cantidadARestar;
                            
                            $input->stock = $stockActual;
                            $input->save();

                            // Registrar salida del almacén en kardex
                            $this->registrarKardexDeposit(
                                $cost['id_input'],
                                'salida',
                                'sales_guide',
                                $guide->id,
                                $cantidadARestar,
                                $stockAnterior,
                                $stockActual,
                                $fechaEmision
                            );

                            // Registrar entrada a la tienda en kardex
                            $this->registrarKardexStore(
                                $validatedData['id_store'],
                                $cost['id_input'],
                                'entrada',
                                'sales_guide',
                                $guide->id,
                                $cantidadARestar,
                                $fechaEmision
                            );
                        }
                    }
                }
            }

            DB::commit();

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

    // Eliminar guía de venta
    public function destroy($id)
    {
        $guide = SalesGuide::findOrFail($id);
        
        // Devolver stock antes de eliminar y registrar en kardex
        $costs = CostSalesGuide::where('id_sales_guide', $guide->id)->get();
        foreach ($costs as $cost) {
            if (!empty($cost->id_input)) {
                $input = Input::find($cost->id_input);
                if ($input) {
                    $cantidadADevolver = floatval($cost->cantidad);
                    $stockAnterior = $input->stock ?? 0;
                    $stockActual = $stockAnterior + $cantidadADevolver;
                    
                    $input->stock = $stockActual;
                    $input->save();

                    // Registrar entrada al almacén por eliminación
                    $this->registrarKardexDeposit(
                        $cost->id_input,
                        'entrada',
                        'sales_guide_delete',
                        $guide->id,
                        $cantidadADevolver,
                        $stockAnterior,
                        $stockActual,
                        now()
                    );

                    // Registrar salida de la tienda por eliminación
                    $this->registrarKardexStore(
                        $guide->id_store,
                        $cost->id_input,
                        'salida',
                        'sales_guide_delete',
                        $guide->id,
                        $cantidadADevolver,
                        now()
                    );
                }
            }
        }
        
        $guide->costSalesGuides()->delete();
        $guide->delete();

        return response()->json([
            'success' => true,
            'message' => 'Guía de venta eliminada exitosamente'
        ]);
    }

    // Mostrar detalle de una guía de venta
    public function show($id)
    {
        $guide = SalesGuide::with([
            'costSalesGuides.input.unit',
            'costSalesGuides.unit',
            'store',
            'deposit',
            'customer',
            'carrier'
        ])->findOrFail($id);

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

    // Datos para selects
    public function selectData()
    {
        return response()->json([
            'success' => true,
            'stores' => Store::all(),
            'deposits' => Deposit::all(),
            'customers' => Customer::all(),
            'carriers' => Carrier::all(),
            'inputs' => Input::with(['unit', 'costInputs.unit'])->get(),
            'units' => Unit::all(),
            'requirements' => Requirement::all(),
        ]);
    }

    /**
     * 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
        $product = Input::find($idProduct);
        if (!$product) return;

        $depositInput = \App\Models\DepositInput::where('id_input', $idProduct)->first();
        $idDeposit = $depositInput ? $depositInput->id_deposit : 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,
        ]);
    }

    /**
     * Registra un movimiento en el kardex de tienda (store)
     */
    private function registrarKardexStore($idStore, $idProduct, $tipoMovimiento, $documentoTipo, $documentoId, $cantidad, $fecha)
    {
        // Obtener stock actual de la tienda para este producto (si existe)
        $ultimoMovimiento = KardexStore::where('id_store', $idStore)
            ->where('id_input', $idProduct)
            ->orderBy('id', 'desc')
            ->first();

        $stockAnterior = $ultimoMovimiento ? $ultimoMovimiento->stock_actual : 0;
        $stockActual = $tipoMovimiento === 'entrada' 
            ? $stockAnterior + $cantidad 
            : $stockAnterior - $cantidad;

        KardexStore::create([
            'id_store' => $idStore,
            '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,
        ]);
    }
}
