<?php

namespace App\Imports;

use App\Models\Producto;
use App\Models\Categoria;
use App\Models\Bodega;
use Maatwebsite\Excel\Concerns\ToModel;
use Maatwebsite\Excel\Concerns\WithHeadingRow;
use Maatwebsite\Excel\Concerns\WithValidation;
use Maatwebsite\Excel\Concerns\SkipsOnFailure;
use Maatwebsite\Excel\Concerns\SkipsOnError;
use Maatwebsite\Excel\Concerns\SkipsFailures;
use Maatwebsite\Excel\Concerns\SkipsErrors;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;

class ProductosImport implements ToModel, WithHeadingRow, WithValidation, SkipsOnFailure, SkipsOnError
{
    use SkipsFailures, SkipsErrors;

    /**
     * Normaliza y prepara los datos antes de la validación.
     */
    public function prepareForValidation($data, $index)
    {
        // Normalizar nombres de columnas
        $normalizedData = [];
        foreach ($data as $key => $value) {
            $normalizedKey = $this->normalizeColumnName($key);
            $normalizedData[$normalizedKey] = $value;
        }
        $data = $normalizedData;

        // Código de barras a string
        if (isset($data['codigo_de_barras']) && is_numeric($data['codigo_de_barras'])) {
            $data['codigo_de_barras'] = (string) $data['codigo_de_barras'];
        }

        // Estado a string
        if (isset($data['estado'])) {
            if (is_bool($data['estado']) || is_numeric($data['estado'])) {
                $data['estado'] = $data['estado'] ? 'Activo' : 'Inactivo';
            }
        }

        // Unidad de medida a string
        if (isset($data['unidad_de_medida']) && !is_string($data['unidad_de_medida'])) {
            $data['unidad_de_medida'] = (string) $data['unidad_de_medida'];
        }

        // Categoría por nombre
        if (!empty($data['categoria_nombre']) && empty($data['categoria_id'])) {
            $categoria = Categoria::firstOrCreate(
                ['nombre' => $data['categoria_nombre']],
                ['descripcion' => 'Categoría creada automáticamente durante importación']
            );
            $data['categoria_id'] = $categoria->id;
        }

        // Categoría (id o nombre)
        if (!empty($data['categoria']) && empty($data['categoria_id'])) {
            if (is_numeric($data['categoria'])) {
                $data['categoria_id'] = $data['categoria'];
            } else {
                $categoria = Categoria::firstOrCreate(
                    ['nombre' => $data['categoria']],
                    ['descripcion' => 'Categoría creada automáticamente durante importación']
                );
                $data['categoria_id'] = $categoria->id;
            }
        }

        return $data;
    }

    /**
     * Normaliza el nombre de una columna.
     */
    private function normalizeColumnName($name)
    {
        $mappings = [
            'código de barras' => 'codigo_de_barras',
            'codigo de barras' => 'codigo_de_barras',
            'categoría' => 'categoria',
            'categoria' => 'categoria',
            'descripción' => 'descripcion',
            'descripcion' => 'descripcion',
            'unidad de medida' => 'unidad_de_medida',
            'stock mínimo' => 'stock_minimo',
            'stock minimo' => 'stock_minimo',
            'stock máximo' => 'stock_maximo',
            'stock maximo' => 'stock_maximo',
            'precio compra' => 'precio_compra',
            'precio venta' => 'precio_venta',
        ];
        $normalized = strtolower(trim($name));
        if (isset($mappings[$normalized])) {
            return $mappings[$normalized];
        }
        $normalized = str_replace(' ', '_', $normalized);
        $normalized = $this->removeAccents($normalized);
        return $normalized;
    }

    /**
     * Elimina tildes.
     */
    private function removeAccents($string)
    {
        $unwanted = [
            'á' => 'a', 'é' => 'e', 'í' => 'i', 'ó' => 'o', 'ú' => 'u',
            'Á' => 'A', 'É' => 'E', 'Í' => 'I', 'Ó' => 'O', 'Ú' => 'U',
            'ñ' => 'n', 'Ñ' => 'N',
        ];
        return strtr($string, $unwanted);
    }

    /**
     * Obtiene el ID de categoría.
     */
    private function getCategoriaId(array $row): ?int
    {
        if (!empty($row['categoria_id']) && is_numeric($row['categoria_id'])) {
            return (int) $row['categoria_id'];
        }
        if (!empty($row['categoria_nombre'])) {
            $cat = Categoria::where('nombre', $row['categoria_nombre'])->first();
            if ($cat) return $cat->id;
        }
        if (!empty($row['categoria'])) {
            if (is_numeric($row['categoria'])) {
                return (int) $row['categoria'];
            }
            $cat = Categoria::where('nombre', $row['categoria'])->first();
            if ($cat) return $cat->id;
        }
        return null;
    }

    /**
     * Parsea unidad de medida.
     */
    private function parseUnidadMedida($value): string
    {
        if (empty($value)) return 'unidad';
        $value = strtolower(trim($value));
        $map = [
            'unidad' => 'unidad',
            'unidades' => 'unidad',
            'u' => 'unidad',
            'docena' => 'docena',
            'docenas' => 'docena',
            'dz' => 'docena',
            'doc' => 'docena',
        ];
        return $map[$value] ?? 'unidad';
    }

    /**
     * Convierte estado a booleano.
     */
    private function parseEstado($value): bool
    {
        if (is_bool($value)) return $value;
        if (is_numeric($value)) return (bool) $value;
        $value = strtolower(trim($value));
        return in_array($value, ['activo', 'active', '1', 'true', 'si', 'yes']);
    }

    /**
     * Crea o actualiza el producto y asigna stock a la bodega.
     */
    public function model(array $row)
    {
        $categoriaId = $this->getCategoriaId($row);

        // Determinar bodega
        $bodegaId = null;
        if (!empty($row['bodega_id'])) {
            $bodegaId = $row['bodega_id'];
        } elseif (!empty($row['bodega'])) {
            $bodega = Bodega::where('nombre', $row['bodega'])->first();
            $bodegaId = $bodega ? $bodega->id : null;
        } else {
            $bodega = Bodega::where('nombre', 'Principal')->first();
            $bodegaId = $bodega ? $bodega->id : null;
        }

        // Actualizar por ID
        if (!empty($row['id']) && is_numeric($row['id'])) {
            $producto = Producto::find($row['id']);
            if ($producto) {
                $producto->update([
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'] ?? null,
                    'codigo_barras' => $row['codigo_de_barras'] ?? null,
                    'categoria_id' => $categoriaId,
                    'precio_compra' => $row['precio_compra'],
                    'precio_venta' => $row['precio_venta'],
                    'stock_minimo' => $row['stock_minimo'] ?? null,
                    'stock_maximo' => $row['stock_maximo'] ?? null,
                    'unidad_medida' => $this->parseUnidadMedida($row['unidad_de_medida'] ?? $row['unidad_medida'] ?? 'unidad'),
                    'estado' => $this->parseEstado($row['estado'] ?? 'Activo'),
                    'imagen' => '',
                ]);
                if ($bodegaId && isset($row['stock'])) {
                    $producto->bodegas()->syncWithoutDetaching([
                        $bodegaId => ['stock' => $row['stock']],
                    ]);
                }
                return null;
            }
        }

        // Actualizar por código de barras
        if (!empty($row['codigo_de_barras'])) {
            $existente = Producto::where('codigo_barras', $row['codigo_de_barras'])->first();
            if ($existente) {
                $existente->update([
                    'nombre' => $row['nombre'],
                    'descripcion' => $row['descripcion'] ?? null,
                    'categoria_id' => $categoriaId,
                    'precio_compra' => $row['precio_compra'],
                    'precio_venta' => $row['precio_venta'],
                    'stock_minimo' => $row['stock_minimo'] ?? null,
                    'stock_maximo' => $row['stock_maximo'] ?? null,
                    'unidad_medida' => $this->parseUnidadMedida($row['unidad_de_medida'] ?? $row['unidad_medida'] ?? 'unidad'),
                    'estado' => $this->parseEstado($row['estado'] ?? 'Activo'),
                    'imagen' => '',
                ]);
                if ($bodegaId && isset($row['stock'])) {
                    $existente->bodegas()->syncWithoutDetaching([
                        $bodegaId => ['stock' => $row['stock']],
                    ]);
                }
                return null;
            }
        }

        // Crear nuevo producto
        $producto = new Producto([
            'nombre' => $row['nombre'],
            'descripcion' => $row['descripcion'] ?? null,
            'codigo_barras' => $row['codigo_de_barras'] ?? null,
            'categoria_id' => $categoriaId,
            'precio_compra' => $row['precio_compra'],
            'precio_venta' => $row['precio_venta'],
            'stock_minimo' => $row['stock_minimo'] ?? null,
            'stock_maximo' => $row['stock_maximo'] ?? null,
            'unidad_medida' => $this->parseUnidadMedida($row['unidad_de_medida'] ?? $row['unidad_medida'] ?? 'unidad'),
            'estado' => $this->parseEstado($row['estado'] ?? 'Activo'),
            'imagen' => '',
        ]);
        $producto->save();
        if ($bodegaId && isset($row['stock'])) {
            $producto->bodegas()->attach($bodegaId, ['stock' => $row['stock']]);
        }
        return $producto;
    }

    /**
     * Reglas de validación.
     */
    public function rules(): array
    {
        return [
            'nombre' => 'required|string|max:255',
            'descripcion' => 'nullable',
            'codigo_de_barras' => 'nullable',
            'categoria_id' => 'required|exists:categorias,id',
            'precio_compra' => 'required|numeric|min:0',
            'precio_venta' => 'required|numeric|min:0',
            'stock' => 'nullable|integer|min:0',
            'stock_minimo' => 'nullable|integer|min:0',
            'stock_maximo' => 'nullable|integer|min:0',
            'unidad_de_medida' => 'nullable',
            'unidad_medida' => 'nullable',
            'estado' => 'nullable',
        ];
    }

    /**
     * Mensajes personalizados.
     */
    public function customValidationMessages()
    {
        return [
            'nombre.required' => 'El nombre del producto es obligatorio.',
            'categoria_id.required' => 'La categoría es obligatoria.',
            'categoria_id.exists' => 'La categoría especificada no existe.',
            'precio_compra.required' => 'El precio de compra es obligatorio.',
            'precio_compra.numeric' => 'El precio de compra debe ser un número.',
            'precio_venta.required' => 'El precio de venta es obligatorio.',
            'precio_venta.numeric' => 'El precio de venta debe ser un número.',
            'stock.integer' => 'El stock debe ser un número entero.',
            'unidad_de_medida.in' => 'La unidad de medida debe ser: unidad o docena.',
        ];
    }
}
