<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class InventarioPrendaDistribucion extends Model
{
    use HasFactory;

    protected $table = 'inventario_prenda_distribuciones';

    protected $fillable = [
        'inventario_prenda_id',
        'bodega_id',
        'proveedor_id',
        'color_id',
        'size_id',
        'cantidad',
    ];

    public function inventarioPrenda()
    {
        return $this->belongsTo(InventarioPrenda::class);
    }

    public function bodega()
    {
        return $this->belongsTo(Bodega::class);
    }

    public function color()
    {
        return $this->belongsTo(Color::class);
    }

    public function size()
    {
        return $this->belongsTo(Size::class);
    }

    protected static function booted()
    {
        // Validaciones: impedir que la suma de distribuciones supere la cantidad terminada
        static::creating(function ($dist) {
            $parentId = $dist->inventario_prenda_id ?? null;
            if (! $parentId) return;

            $parent = \App\Models\InventarioPrenda::find($parentId);
            if (! $parent) return;

            $cantidad = intval($dist->cantidad ?? 0);
            $sumExistentes = (int) self::where('inventario_prenda_id', $parentId)->sum('cantidad');

            // Validar contra la cantidad terminada total (no distribuir más del total entregado)
            if (($sumExistentes + $cantidad) > (int) $parent->cantidad_terminada) {
                throw \Illuminate\Validation\ValidationException::withMessages([
                    'cantidad' => 'No se puede añadir más prendas que las disponibles.',
                ]);
            }
        });

        static::updating(function ($dist) {
            $parentId = $dist->inventario_prenda_id ?? null;
            if (! $parentId) return;

            $parent = \App\Models\InventarioPrenda::find($parentId);
            if (! $parent) return;

            $newCantidad = intval($dist->cantidad ?? 0);
            $othersSum = (int) self::where('inventario_prenda_id', $parentId)
                ->where('id', '<>', $dist->id)
                ->sum('cantidad');

            // Validar contra la cantidad terminada total (no distribuir más del total entregado)
            if (($othersSum + $newCantidad) > (int) $parent->cantidad_terminada) {
                throw \Illuminate\Validation\ValidationException::withMessages([
                    'cantidad' => 'No se puede añadir más prendas que las disponibles.',
                ]);
            }
        });

        // Al crear una distribución, incrementar stock
        static::created(function ($dist) {
            $cantidad = $dist->cantidad ?? 0;
            if ($cantidad <= 0) return;

            $bodegaId = $dist->bodega_id;

            // If a proveedor_id is present, treat as assignment to a provider/person (no warehouse stock changes)
            if ($dist->proveedor_id && ! $bodegaId) {
                // Just decrement disponibilidad on parent
                $parent = $dist->inventarioPrenda;
                if ($parent) {
                    $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad);
                    $parent->save();
                }

                return;
            }

            if ($dist->color_id && $dist->size_id) {
                // Variante
                // Determinar producto: preferir inventario.prenda.producto_id -> op.producto_id
                $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);

                // Si no existe producto, intentar crear/inferrir desde la Orden de Producción
                if (! $productoId && $dist->inventarioPrenda && $dist->inventarioPrenda->ordenProduccion) {
                    $op = $dist->inventarioPrenda->ordenProduccion;
                    $nombre = $op->prenda_modelo ?? $op->referencia ?? ('Producto OP #' . $op->id);

                    $codigo = 'AUTOD-' . $op->id . '-' . time();
                    $codigo = substr($codigo, 0, 50);
                    while (\App\Models\Producto::where('codigo_barras', $codigo)->exists()) {
                        $codigo .= '-' . rand(0, 9);
                        $codigo = substr($codigo, 0, 50);
                    }

                    $producto = \App\Models\Producto::firstOrCreate(
                        ['nombre' => $nombre],
                        [
                            'descripcion' => 'Creado automáticamente desde distribución (OP #' . $op->id . ')',
                            'stock' => 0,
                            'estado' => true,
                            'precio_compra' => 0,
                            'precio_venta' => 0,
                            'unidad_medida' => 'unidad',
                            'codigo_barras' => $codigo,
                        ]
                    );

                    $productoId = $producto->id;

                    // Guardar producto en el inventario padre para futuras referencias
                    $parent = $dist->inventarioPrenda;
                    if ($parent && ! $parent->producto_id) {
                        $parent->producto_id = $productoId;
                        $parent->save();
                    }
                }

                $variant = \App\Models\ProductVariant::firstOrCreate([
                    'producto_id' => $productoId,
                    'color_id' => $dist->color_id,
                    'size_id' => $dist->size_id,
                ], ['stock' => 0, 'sku' => 'AUTO-'.uniqid(), 'barcode' => '']);

                $existing = \DB::table('variante_bodega')
                    ->where('variante_id', $variant->id)
                    ->where('bodega_id', $bodegaId)
                    ->first();

                if ($existing) {
                    \DB::table('variante_bodega')
                        ->where('variante_id', $variant->id)
                        ->where('bodega_id', $bodegaId)
                        ->update(['stock' => ($existing->stock ?? 0) + $cantidad, 'updated_at' => now()]);
                } else {
                    \DB::table('variante_bodega')->insert(['variante_id' => $variant->id, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]);
                }

                $variant->increment('stock', $cantidad);

                // Reducir disponibilidad en inventario_prenda
                $parent = $dist->inventarioPrenda;
                if ($parent) {
                    $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad);
                    $parent->save();
                }
            } else {
                // Producto
                $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);

                // Si no existe producto, intentar crear/inferrir desde la Orden de Producción
                if (! $productoId && $dist->inventarioPrenda && $dist->inventarioPrenda->ordenProduccion) {
                    $op = $dist->inventarioPrenda->ordenProduccion;
                    $nombre = $op->prenda_modelo ?? $op->referencia ?? ('Producto OP #' . $op->id);

                    $codigo = 'AUTOP-' . $op->id . '-' . time();
                    $codigo = substr($codigo, 0, 50);
                    while (\App\Models\Producto::where('codigo_barras', $codigo)->exists()) {
                        $codigo .= '-' . rand(0, 9);
                        $codigo = substr($codigo, 0, 50);
                    }

                    $producto = \App\Models\Producto::create([
                        'nombre' => $nombre,
                        'descripcion' => 'Creado automáticamente desde distribución (OP #' . $op->id . ')',
                        'stock' => 0,
                        'estado' => true,
                        'precio_compra' => 0,
                        'precio_venta' => 0,
                        'unidad_medida' => 'unidad',
                        'codigo_barras' => $codigo,
                        'categoria_id' => \App\Models\Categoria::first()?->id ?? \App\Models\Categoria::create(['nombre' => 'Generica'])->id,
                    ]);

                    $productoId = $producto->id;

                    // Guardar producto en el inventario padre para futuras referencias
                    $parent = $dist->inventarioPrenda;
                    if ($parent && ! $parent->producto_id) {
                        $parent->producto_id = $productoId;
                        $parent->save();
                    }
                }

                if ($productoId) {
                    $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first();
                    if ($existing) {
                        \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $cantidad, 'updated_at' => now()]);
                    } else {
                        \DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => $cantidad, 'created_at' => now(), 'updated_at' => now()]);
                    }

                    // Nota: No incrementamos el stock global del producto aquí — el stock global ya se incrementó cuando se creó el InventarioPrenda.

                    // Reducir disponibilidad en inventario_prenda
                    $parent = $dist->inventarioPrenda;
                    if ($parent) {
                        $parent->cantidad_disponible = max(0, $parent->cantidad_disponible - $cantidad);
                        $parent->save();
                    }
                }
            }
        });

        // Al actualizar, ajustar la diferencia
        static::updated(function ($dist) {
            $original = $dist->getOriginal();
            $oldCantidad = intval($original['cantidad'] ?? 0);
            $newCantidad = intval($dist->cantidad ?? 0);
            $delta = $newCantidad - $oldCantidad;
            if ($delta == 0) return;

            $bodegaId = $dist->bodega_id;

            if ($dist->color_id && $dist->size_id) {
                $variant = \App\Models\ProductVariant::firstOrCreate([
                    'producto_id' => $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null),
                    'color_id' => $dist->color_id,
                    'size_id' => $dist->size_id,
                ], ['stock' => 0, 'sku' => 'AUTO-'.uniqid(), 'barcode' => '']);

                $existing = \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->first();
                if ($existing) {
                    \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $delta, 'updated_at' => now()]);
                } else {
                    \DB::table('variante_bodega')->insert(['variante_id' => $variant->id, 'bodega_id' => $bodegaId, 'stock' => max(0, $delta), 'created_at' => now(), 'updated_at' => now()]);
                }

                $variant->increment('stock', $delta);

                $parent = $dist->inventarioPrenda;
                if ($parent) {
                    $parent->cantidad_disponible = max(0, min($parent->cantidad_terminada, $parent->cantidad_disponible - $delta));
                    $parent->save();
                }
            } else {
                $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);
                if ($productoId) {
                    $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first();
                    if ($existing) {
                        \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => ($existing->stock ?? 0) + $delta, 'updated_at' => now()]);
                    } else {
                        \DB::table('producto_bodega')->insert(['producto_id' => $productoId, 'bodega_id' => $bodegaId, 'stock' => max(0, $delta), 'created_at' => now(), 'updated_at' => now()]);
                    }

                    $prod = \App\Models\Producto::find($productoId);
                    if ($prod && ! $prod->variants()->exists()) {
                        $prod->increment('stock', $delta);
                    }

                    $parent = $dist->inventarioPrenda;
                    if ($parent) {
                        $parent->cantidad_disponible = max(0, min($parent->cantidad_terminada, $parent->cantidad_disponible - $delta));
                        $parent->save();
                    }
                }
            }
        });

        // Al eliminar, restar la cantidad
        static::deleted(function ($dist) {
            $cantidad = $dist->cantidad ?? 0;
            if ($cantidad <= 0) return;

            $bodegaId = $dist->bodega_id;

            if ($dist->color_id && $dist->size_id) {
                $variant = \App\Models\ProductVariant::where('color_id', $dist->color_id)->where('size_id', $dist->size_id)->first();
                if ($variant) {
                    $existing = \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->first();
                    if ($existing) {
                        $newStock = max(0, ($existing->stock ?? 0) - $cantidad);
                        \DB::table('variante_bodega')->where('variante_id', $variant->id)->where('bodega_id', $bodegaId)->update(['stock' => $newStock, 'updated_at' => now()]);
                    }

                    $variant->decrement('stock', $cantidad);

                    // Restaurar disponibilidad en inventario_prenda
                    $parent = $dist->inventarioPrenda;
                    if ($parent) {
                        $parent->cantidad_disponible = min($parent->cantidad_terminada, $parent->cantidad_disponible + $cantidad);
                        $parent->save();
                    }
                }
            } else {
                $productoId = $dist->inventarioPrenda->producto_id ?? ($dist->inventarioPrenda->ordenProduccion->producto_id ?? null);
                if ($productoId) {
                    $existing = \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->first();
                    if ($existing) {
                        $newStock = max(0, ($existing->stock ?? 0) - $cantidad);
                        \DB::table('producto_bodega')->where('producto_id', $productoId)->where('bodega_id', $bodegaId)->update(['stock' => $newStock, 'updated_at' => now()]);
                    }

                    $prod = \App\Models\Producto::find($productoId);
                    if ($prod && ! $prod->variants()->exists()) {
                        $prod->decrement('stock', $cantidad);
                    }

                    // Restaurar disponibilidad en inventario_prenda
                    $parent = $dist->inventarioPrenda;
                    if ($parent) {
                        $parent->cantidad_disponible = min($parent->cantidad_terminada, $parent->cantidad_disponible + $cantidad);
                        $parent->save();
                    }
                }
            }
        });
    }
}
