<?php

namespace App\Models;

use Filament\Actions\Concerns\BelongsToGroup;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Database\Eloquent\Relations\BelongsToMany;

class Producto extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array
     */
    protected $fillable = [
        'nombre',
        'descripcion',
        'codigo_barras',
        'precio_compra',
        'precio_venta',
        'stock',
        'categoria_id', 
        'estado',
        'imagen',
        'stock_minimo',
        'stock_maximo',
        'unidad_medida'
    ];

    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'id' => 'integer',
        'estado' => 'boolean',
    ];

    /**
     * Valores por defecto para atributos del modelo
     */
    protected $attributes = [
        'imagen' => '',
    ];

    public function variants(): HasMany
    {
        return $this->hasMany(ProductVariant::class);
    }
    public function categoria(): BelongsTo
    {
        return $this->belongsTo(Categoria::class);
    }

    /**
     * Relación many-to-many con bodegas
     */
    public function bodegas(): BelongsToMany
    {
        return $this->belongsToMany(Bodega::class, 'producto_bodega')
                    ->withPivot('stock')
                    ->withTimestamps();
    }

    /**
     * Obtiene las unidades de medida disponibles
     */
    public static function getUnidadesMedida(): array
    {
        return [
            'unidad' => 'Unidad (1)',
            'docena' => 'Docena (12)',
        ];
    }

    /**
     * Obtiene el factor de conversión para una unidad de medida
     */
    public static function getFactorConversion(string $unidad): int
    {
        $factores = [
            'unidad' => 1,
            'docena' => 12,
        ];

        return $factores[$unidad] ?? 1;
    }

    /**
     * Convierte una cantidad en la unidad especificada a unidades individuales
     */
    public static function convertirAUnidades(float $cantidad, string $unidad): int
    {
        return (int) ($cantidad * self::getFactorConversion($unidad));
    }

    /**
     * Convierte unidades individuales a la unidad de medida especificada
     */
    public static function convertirDesdeUnidades(int $unidades, string $unidad): float
    {
        $factor = self::getFactorConversion($unidad);
        return $factor > 1 ? round($unidades / $factor, 2) : $unidades;
    }

    /**
     * Obtiene el stock en la unidad de medida configurada
     */
    public function getStockEnUnidadMedida(): float
    {
        $stockTotal = $this->variants()->exists() 
            ? $this->variants()->sum('stock') 
            : $this->stock;
            
        return self::convertirDesdeUnidades($stockTotal, $this->unidad_medida ?? 'unidad');
    }

    /**
     * Obtiene el nombre de la unidad de medida
     */
    public function getNombreUnidadMedida(): string
    {
        $unidades = self::getUnidadesMedida();
        return $unidades[$this->unidad_medida ?? 'unidad'] ?? 'Unidad (1)';
    }

    /**
     * Obtener el stock total en todas las bodegas
     */
    public function getStockTotalBodegas(): int
    {
        return $this->bodegas()->sum('producto_bodega.stock');
    }

    /**
     * Obtener el stock en una bodega específica
     */
    public function getStockEnBodega(int $bodegaId): int
    {
        $bodega = $this->bodegas()->where('bodega_id', $bodegaId)->first();
        return $bodega ? $bodega->pivot->stock : 0;
    }

    /**
     * Obtener el stock total en una bodega específica (considerando variantes)
     */
    public function getStockTotalEnBodega(int $bodegaId): int
    {
        if ($this->variants()->exists()) {
            $stockVariantes = 0;
            foreach ($this->variants as $variante) {
                $bodegaVariante = $variante->bodegas()->where('bodega_id', $bodegaId)->first();
                if ($bodegaVariante) {
                    $stockVariantes += $bodegaVariante->pivot->stock;
                }
            }
            return $stockVariantes;
        } else {
            return $this->getStockEnBodega($bodegaId);
        }
    }

    /**
     * Distribuir stock total entre bodegas
     */
    public function distribuirStock(array $distribucion): void
    {
        foreach ($distribucion as $bodegaId => $stock) {
            $this->bodegas()->syncWithoutDetaching([
                $bodegaId => ['stock' => $stock]
            ]);
        }
    }

    /**
     * Obtener el stock efectivo (considerando bodegas Y variantes correctamente)
     */
    public function getStockEfectivo(): int
    {
        // Si tiene variantes, el stock se calcula desde las variantes
        if ($this->variants()->exists()) {
            $stockVariantes = 0;
            
            foreach ($this->variants as $variante) {
                $stockVariantes += $variante->getStockEfectivo();
            }
            
            return $stockVariantes;
        } else {
            // Para productos sin variantes
            if ($this->bodegas()->exists()) {
                return $this->getStockTotalBodegas();
            } else {
                return $this->stock;
            }
        }
    }

    /**
     * Accessor para código de barras dinámico
     */
    public function getCodigoBarrasAttribute($value)
    {
        // Si el producto tiene variantes, el código de barras es NULL
        if ($this->variants()->exists()) {
            return null;
        }

        // Si NO tiene variantes, usa su código de barras propio
        return $value;
    }

    /**
     * Accessor para stock dinámico
     * Si el producto tiene variantes, el stock directo debe ser 0
     */
    public function getStockAttribute($value)
    {
        // Si el producto tiene variantes, el stock directo debe ser 0
        if ($this->variants()->exists()) {
            return 0;
        }

        // Si NO tiene variantes, devuelve el stock real
        return $value;
    }

    /**
     * Mutator para stock - evita que se asigne stock directo si hay variantes
     */
    public function setStockAttribute($value)
    {
        // Si el producto ya tiene variantes, no permitir stock directo
        if ($this->exists && $this->variants()->exists()) {
            $this->attributes['stock'] = 0;
        } else {
            $this->attributes['stock'] = $value;
        }
    }

    /**
     * Relación con detalles de compra
     */
    public function detalleCompras(): HasMany
    {
        return $this->hasMany(DetalleCompra::class);
    }

    /**
     * Relación con detalles de venta
     */
    public function detalleVentas(): HasMany
    {
        return $this->hasMany(DetalleVenta::class);
    }
}
