using Core.Interfaces.Stock;    // ILSStockScanDom
using Domain.Dtos.Stock;        // StockItemSearchParams, StockItemScanResultDto
using Domain.Generics;          // PagedResult<T>
using Microsoft.AspNetCore.Mvc;
using Transversal.Services;

namespace API.Controllers.Stock
{
    [Route("api/[controller]")]
    [ApiController]
    public class LSStockScanController : ControllerBase
    {
        private readonly ILSStockScanDom _service;

        public LSStockScanController(ILSStockScanDom service)
        {
            _service = service;
        }

        /// <summary>
        /// Búsqueda paginada de ítems de stock por código/texto, lote y filtros opcionales.
        /// </summary>
        [HttpPost("search")]
        public async Task<ActionResult<PagedResult<StockItemScanResultDto>>> Search([FromBody] StockItemSearchParams searchParams)
        {
            var result = await _service.SearchAsync(searchParams);
            return Ok(result);
        }

        /// Realiza una búsqueda paginada de ítems de stock utilizando datos ya parseados 
        /// (por ejemplo, provenientes de un código GS1 escaneado).
        /// </summary>
        /// <param name="searchParams">
        /// Parámetros de búsqueda ya procesados y listos para filtrar en base de datos, 
        /// incluyendo código de producto, lote, fecha de vencimiento, ubicación, etc.
        /// </param>
        /// <returns>
        /// Lista paginada de ítems de stock que cumplen con los filtros especificados.
        /// </returns>

        [HttpPost("search-parsed")]
        public async Task<ActionResult<PagedResult<StockItemScanResultDto>>> SearchParsed([FromBody] StockItemParsedSearchParams searchParams)
        {
            var result = await _service.SearchParsedAsync(searchParams);
            return Ok(result);
        }

        /// <summary>
        /// Recibe un escaneo RAW (GS1-128/DataMatrix), lo parsea y ejecuta la búsqueda paginada.
        /// </summary>
        [HttpPost("parse-and-search")]
        public async Task<ActionResult<PagedResult<StockItemScanResultDto>>> ParseAndSearch([FromBody] StockScanRawRequest req)
        {
            if (req is null || string.IsNullOrWhiteSpace(req.Raw))
                return BadRequest("Raw is required.");

            var raw = req.Raw.Trim();

            // 1) Parseo GS1
            var parsed = Gs1CodeParser.Parse(raw);

            // 2) ¿Hay AIs útiles?
            bool hasAis =
                   !string.IsNullOrWhiteSpace(parsed.Lot)
                || parsed.ExpirationDate.HasValue
                || !string.IsNullOrWhiteSpace(parsed.Serial)
                || !string.IsNullOrWhiteSpace(parsed.Variant);

            // 3) Elegir "code" con prioridades
            string? code = LooksLikeGtin(parsed.Gtin) ? parsed.Gtin : null;

            // Opcional: si NO hay serial y querés usar Variant como último intento:
            // if (code is null && string.IsNullOrWhiteSpace(parsed.Serial))
            //     code = parsed.Variant;

            // Fallback a "código plano" (ej. factory/regulatory tipeado) si no hay AIs ni GTIN
            if (code is null && !hasAis && IsPlainCode(raw))
                code = raw;

            // 4) Armar parámetros de búsqueda
            var sp = new StockItemParsedSearchParams
            {
                Gtin = code, // tratado como "code" genérico en el repo
                Batch = string.IsNullOrWhiteSpace(parsed.Lot) ? null : parsed.Lot,
                Expiration = parsed.ExpirationDate.HasValue ? DateOnly.FromDateTime(parsed.ExpirationDate.Value) : (DateOnly?)null,
                Serial = string.IsNullOrWhiteSpace(parsed.Serial) ? null : parsed.Serial,
                LocationId = req.LocationId,
                Page = req.Page <= 0 ? 1 : req.Page,
                PageSize = req.PageSize <= 0 ? 10 : req.PageSize
            };

            // 5) Delegar al servicio existente
            var result = await _service.SearchParsedAsync(sp);
            return Ok(result);

            // === Helpers locales ===
            static bool LooksLikeGtin(string? x)
                => !string.IsNullOrWhiteSpace(x)
                && x!.All(char.IsDigit)
                && (x.Length == 8 || x.Length == 12 || x.Length == 13 || x.Length == 14);

            static bool IsPlainCode(string s)
            {
                if (string.IsNullOrWhiteSpace(s)) return false;
                if (s.Contains('$') || s.Contains((char)29) || s.Contains(' ')) return false; // FNC1/espacios
                var prefix = s.Length >= 2 ? s[..2] : s;
                if (prefix is "01" or "10" or "11" or "17" or "21" or "22") return false;     // evita confundir AIs
                return s.All(c => char.IsLetterOrDigit(c) || c is '-' or '/' or '_');         // agrega '.' si lo necesitás
            }
        }

    }
}
