<?php

namespace App\Http\Requests;

use App\Models\Producto;
use App\Support\OrdenLavanderiaDetalleLineValidator;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\ValidationException;

/**
 * Misma validación de líneas que crear orden con ítems (sin cliente ni caja).
 */
class LaundryPosPreviewTotalsRequest extends FormRequest
{
    public function authorize(): bool
    {
        return $this->user()?->can('pos.vender') ?? false;
    }

    /**
     * @return array<string, mixed>
     */
    public function rules(): array
    {
        return [
            'items' => ['required', 'array', 'min:1'],
            'items.*.producto_id' => ['nullable', 'integer', 'exists:productos,id'],
            'items.*.laundry_sale_product_id' => ['nullable', 'integer', 'exists:laundry_sale_products,id'],
            'items.*.etapa_id' => ['nullable', 'integer', 'exists:etapas,id'],
            'items.*.precio_unitario' => ['nullable', 'numeric', 'min:0'],
            'items.*.cantidad' => ['required', 'numeric', 'min:0.001'],
            'items.*.garment_type_id' => ['nullable', 'integer', 'exists:garment_types,id'],
            'items.*.load_type_id' => ['nullable', 'integer', 'exists:load_types,id'],
            'items.*.billing_mode' => ['nullable', 'in:by_garment_type,by_weight'],
            'items.*.weight_kg' => ['nullable', 'numeric', 'min:0'],
            'items.*.observations' => ['nullable', 'string', 'max:2000'],
            'items.*.extra_cost' => ['nullable', 'numeric', 'min:0'],
            'items.*.precio_unitario_override' => ['nullable', 'numeric', 'min:0'],
            'items.*.is_informational' => ['nullable', 'boolean'],
        ];
    }

    public function withValidator($validator): void
    {
        $validator->after(function ($validator): void {
            if ($validator->errors()->isNotEmpty()) {
                return;
            }
            $items = $this->input('items', []);
            if (! is_array($items)) {
                return;
            }
            foreach ($items as $idx => $item) {
                if (! is_array($item)) {
                    continue;
                }
                $isInformational = OrdenLavanderiaDetalleLineValidator::isInformationalItem($item);
                $hasProducto = ! empty($item['producto_id']);
                $hasSaleProduct = ! empty($item['laundry_sale_product_id']) && ! $isInformational;
                if ($isInformational) {
                    continue;
                }
                if ($hasProducto && $hasSaleProduct) {
                    $validator->errors()->add(
                        "items.{$idx}.laundry_sale_product_id",
                        'No combine producto_id (legacy) con laundry_sale_product_id en la misma línea.'
                    );
                }
                if ($hasProducto && ! empty($item['etapa_id'])) {
                    $validator->errors()->add(
                        "items.{$idx}.producto_id",
                        'No combine producto_id con etapa_id en la misma línea. Use catálogo productos O línea solo lavandería TIBU.'
                    );
                }
                if ($hasSaleProduct && ! empty($item['garment_type_id'])) {
                    $validator->errors()->add(
                        "items.{$idx}.garment_type_id",
                        'No combine garment_type_id con laundry_sale_product_id (catálogo POS).'
                    );
                }
                if (! $hasProducto && ! $hasSaleProduct && empty($item['etapa_id'])) {
                    $validator->errors()->add(
                        "items.{$idx}.producto_id",
                        'Cada línea debe incluir producto_id (legacy), laundry_sale_product_id (catálogo POS) o etapa_id (TIBU por prenda).'
                    );
                }
            }
            if ($validator->errors()->isNotEmpty()) {
                return;
            }
            try {
                OrdenLavanderiaDetalleLineValidator::validateItems($items);
            } catch (ValidationException $e) {
                foreach ($e->errors() as $key => $messages) {
                    foreach ($messages as $msg) {
                        $validator->errors()->add($key, $msg);
                    }
                }
            }
            if ($validator->errors()->isNotEmpty()) {
                return;
            }
            $idsProducto = collect($items)->pluck('producto_id')->filter(fn ($id) => $id !== null && $id !== '')->map(fn ($id) => (int) $id)->unique()->values()->all();
            $productos = $idsProducto === [] ? collect() : Producto::whereIn('id', $idsProducto)->get();
            foreach ($items as $idx => $item) {
                if (empty($item['producto_id'])) {
                    continue;
                }
                $p = $productos->firstWhere('id', (int) $item['producto_id']);
                if ($p && ! $p->es_servicio && $p->stock < (int) round((float) $item['cantidad'], 0)) {
                    $validator->errors()->add(
                        "items.{$idx}.cantidad",
                        "Stock insuficiente para {$p->nombre}. Disponible: {$p->stock}."
                    );
                }
            }
        });
    }
}
