<?php

namespace App\Services;

use App\Models\Producto;
use App\Models\ProductVariant;
use App\Models\Bodega;
use App\Models\TransferenciaBodega;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
use Exception;

class TransferenciaBodegaService
{
    /**
     * Realizar transferencia de stock entre bodegas
     *
     * @param int $productoId
     * @param int $bodegaOrigenId
     * @param int $bodegaDestinoId
     * @param int $cantidad
     * @param string|null $motivo
     * @return TransferenciaBodega
     * @throws Exception
     */
    public function transferir(
        int $productoId,
        int $bodegaOrigenId,
        int $bodegaDestinoId,
        int $cantidad,
        ?string $motivo = null
    ): TransferenciaBodega {
        
        if ($cantidad <= 0) {
            throw new Exception('La cantidad debe ser mayor a 0');
        }

        if ($bodegaOrigenId === $bodegaDestinoId) {
            throw new Exception('La bodega de origen y destino no pueden ser la misma');
        }

        $producto = Producto::findOrFail($productoId);
        $bodegaOrigen = Bodega::findOrFail($bodegaOrigenId);
        $bodegaDestino = Bodega::findOrFail($bodegaDestinoId);

        DB::beginTransaction();

        try {
            // Verificar que la bodega origen tiene suficiente stock
            $stockOrigen = $this->obtenerStockEnBodega($producto, $bodegaOrigen);
            
            if ($stockOrigen < $cantidad) {
                throw new Exception(
                    "Stock insuficiente en {$bodegaOrigen->nombre}. " .
                    "Disponible: {$stockOrigen}, Solicitado: {$cantidad}"
                );
            }

            // Reducir stock en bodega origen
            $this->actualizarStockBodega($producto, $bodegaOrigen, $stockOrigen - $cantidad);

            // Aumentar stock en bodega destino
            $stockDestino = $this->obtenerStockEnBodega($producto, $bodegaDestino);
            $this->actualizarStockBodega($producto, $bodegaDestino, $stockDestino + $cantidad);

            // Crear registro de transferencia
            $transferencia = TransferenciaBodega::create([
                'producto_id' => $productoId,
                'bodega_origen_id' => $bodegaOrigenId,
                'bodega_destino_id' => $bodegaDestinoId,
                'cantidad' => $cantidad,
                'motivo' => $motivo,
                'usuario_id' => Auth::id() ?? 1, // Fallback a usuario administrador si no hay autenticación
                'fecha_transferencia' => now(),
            ]);

            DB::commit();

            return $transferencia;

        } catch (Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Obtener el stock de un producto en una bodega específica
     *
     * @param Producto $producto
     * @param Bodega $bodega
     * @return int
     */
    private function obtenerStockEnBodega(Producto $producto, Bodega $bodega): int
    {
        $relacion = $producto->bodegas()->where('bodega_id', $bodega->id)->first();
        return $relacion ? $relacion->pivot->stock : 0;
    }

    /**
     * Actualizar el stock de un producto en una bodega
     *
     * @param Producto $producto
     * @param Bodega $bodega
     * @param int $nuevoStock
     * @return void
     */
    private function actualizarStockBodega(Producto $producto, Bodega $bodega, int $nuevoStock): void
    {
        $existeRelacion = $producto->bodegas()->where('bodega_id', $bodega->id)->exists();

        if ($existeRelacion) {
            // Actualizar relación existente
            $producto->bodegas()->updateExistingPivot($bodega->id, [
                'stock' => $nuevoStock
            ]);
        } else {
            // Crear nueva relación (solo si el stock es mayor a 0)
            if ($nuevoStock > 0) {
                $producto->bodegas()->attach($bodega->id, [
                    'stock' => $nuevoStock
                ]);
            }
        }
    }

    /**
     * Obtener el historial de transferencias de un producto
     *
     * @param int $productoId
     * @param int $limit
     * @return \Illuminate\Database\Eloquent\Collection
     */
    public function obtenerHistorialTransferencias(int $productoId, int $limit = 50)
    {
        return TransferenciaBodega::with(['bodegaOrigen', 'bodegaDestino', 'usuario'])
            ->where('producto_id', $productoId)
            ->orderBy('fecha_transferencia', 'desc')
            ->limit($limit)
            ->get();
    }

    /**
     * Obtener resumen de stock por bodega para un producto
     *
     * @param int $productoId
     * @return array
     */
    public function obtenerResumenStockPorBodega(int $productoId): array
    {
        $producto = Producto::with('bodegas')->findOrFail($productoId);
        
        $resumen = [];
        foreach ($producto->bodegas as $bodega) {
            $resumen[] = [
                'bodega_id' => $bodega->id,
                'bodega_nombre' => $bodega->nombre,
                'stock' => $bodega->pivot->stock,
            ];
        }

        return $resumen;
    }

    /**
     * Obtener resumen de stock considerando variantes
     *
     * @param int $productoId
     * @return array
     */
    public function obtenerResumenStockCompleto(int $productoId): array
    {
        $producto = Producto::with(['bodegas', 'variants.bodegas'])->findOrFail($productoId);
        
        $resumen = [
            'producto' => [
                'id' => $producto->id,
                'nombre' => $producto->nombre,
                'tiene_variantes' => $producto->variants()->exists(),
                'stock_efectivo' => $producto->getStockEfectivo(),
            ],
            'distribuciones' => []
        ];

        if ($producto->variants()->exists()) {
            // Producto con variantes
            foreach ($producto->variants as $variante) {
                $stockVariante = $variante->getStockEfectivo();
                
                $distribucionVariante = [
                    'variante_id' => $variante->id,
                    'sku' => $variante->sku,
                    'stock_total' => $stockVariante,
                    'bodegas' => []
                ];

                if ($variante->bodegas()->exists()) {
                    foreach ($variante->bodegas as $bodega) {
                        $distribucionVariante['bodegas'][] = [
                            'bodega_id' => $bodega->id,
                            'bodega_nombre' => $bodega->nombre,
                            'stock' => $bodega->pivot->stock,
                        ];
                    }
                } else {
                    // Stock directo de la variante
                    $distribucionVariante['stock_directo'] = $variante->stock;
                }

                $resumen['distribuciones'][] = $distribucionVariante;
            }
        } else {
            // Producto sin variantes
            if ($producto->bodegas()->exists()) {
                foreach ($producto->bodegas as $bodega) {
                    $resumen['distribuciones'][] = [
                        'bodega_id' => $bodega->id,
                        'bodega_nombre' => $bodega->nombre,
                        'stock' => $bodega->pivot->stock,
                    ];
                }
            } else {
                $resumen['stock_directo'] = $producto->stock;
            }
        }

        return $resumen;
    }

    /**
     * Transferir variantes entre bodegas
     *
     * @param int $varianteId
     * @param int $bodegaOrigenId  
     * @param int $bodegaDestinoId
     * @param int $cantidad
     * @param string|null $motivo
     * @return TransferenciaBodega
     * @throws Exception
     */
    public function transferirVariante(
        int $varianteId,
        int $bodegaOrigenId,
        int $bodegaDestinoId,
        int $cantidad,
        ?string $motivo = null
    ): TransferenciaBodega {
        
        if ($cantidad <= 0) {
            throw new Exception('La cantidad debe ser mayor a 0');
        }

        if ($bodegaOrigenId === $bodegaDestinoId) {
            throw new Exception('La bodega de origen y destino no pueden ser la misma');
        }

        $variante = ProductVariant::findOrFail($varianteId);
        $bodegaOrigen = Bodega::findOrFail($bodegaOrigenId);
        $bodegaDestino = Bodega::findOrFail($bodegaDestinoId);

        DB::beginTransaction();

        try {
            // Verificar que la bodega origen tiene suficiente stock
            $stockOrigen = $this->obtenerStockVarianteEnBodega($variante, $bodegaOrigen);
            
            if ($stockOrigen < $cantidad) {
                throw new Exception(
                    "Stock insuficiente en {$bodegaOrigen->nombre}. " .
                    "Disponible: {$stockOrigen}, Solicitado: {$cantidad}"
                );
            }

            // Reducir stock en bodega origen
            $this->actualizarStockVarianteBodega($variante, $bodegaOrigen, $stockOrigen - $cantidad);

            // Aumentar stock en bodega destino
            $stockDestino = $this->obtenerStockVarianteEnBodega($variante, $bodegaDestino);
            $this->actualizarStockVarianteBodega($variante, $bodegaDestino, $stockDestino + $cantidad);

            // Crear registro de transferencia
            $transferencia = TransferenciaBodega::create([
                'variante_id' => $varianteId,
                'producto_id' => $variante->producto_id,
                'bodega_origen_id' => $bodegaOrigenId,
                'bodega_destino_id' => $bodegaDestinoId,
                'cantidad' => $cantidad,
                'motivo' => $motivo ? "Variante: {$motivo}" : "Transferencia de variante {$variante->sku}",
                'usuario_id' => Auth::id() ?? 1, // Fallback a usuario administrador si no hay autenticación
                'fecha_transferencia' => now(),
            ]);

            DB::commit();

            return $transferencia;

        } catch (Exception $e) {
            DB::rollBack();
            throw $e;
        }
    }

    /**
     * Obtener el stock de una variante en una bodega específica
     *
     * @param ProductVariant $variante
     * @param Bodega $bodega
     * @return int
     */
    private function obtenerStockVarianteEnBodega(ProductVariant $variante, Bodega $bodega): int
    {
        $relacion = $variante->bodegas()->where('bodega_id', $bodega->id)->first();
        return $relacion ? $relacion->pivot->stock : 0;
    }

    /**
     * Actualizar el stock de una variante en una bodega
     *
     * @param ProductVariant $variante
     * @param Bodega $bodega
     * @param int $nuevoStock
     * @return void
     */
    private function actualizarStockVarianteBodega(ProductVariant $variante, Bodega $bodega, int $nuevoStock): void
    {
        $existeRelacion = $variante->bodegas()->where('bodega_id', $bodega->id)->exists();

        if ($existeRelacion) {
            // Actualizar relación existente
            $variante->bodegas()->updateExistingPivot($bodega->id, [
                'stock' => $nuevoStock
            ]);
        } else {
            // Crear nueva relación (solo si el stock es mayor a 0)
            if ($nuevoStock > 0) {
                $variante->bodegas()->attach($bodega->id, [
                    'stock' => $nuevoStock
                ]);
            }
        }
    }

    /**
     * Obtener resumen de stock por bodega para una variante
     *
     * @param int $varianteId
     * @return array
     */
    public function obtenerResumenStockVariante(int $varianteId): array
    {
        $variante = ProductVariant::with(['bodegas', 'producto'])->findOrFail($varianteId);
        
        $resumen = [
            'variante_id' => $varianteId,
            'variante_sku' => $variante->sku,
            'producto_nombre' => $variante->producto->nombre,
            'stock_total' => $variante->getStockEfectivo(),
            'bodegas' => []
        ];

        if ($variante->bodegas()->exists()) {
            foreach ($variante->bodegas as $bodega) {
                $resumen['bodegas'][] = [
                    'bodega_id' => $bodega->id,
                    'bodega_nombre' => $bodega->nombre,
                    'stock' => $bodega->pivot->stock,
                ];
            }
        } else {
            $resumen['stock_directo'] = $variante->stock;
        }

        return $resumen;
    }
}