using Apollinare.API.Services;
using Apollinare.Domain.Entities;
using Microsoft.AspNetCore.Mvc;

namespace Apollinare.API.Controllers;

[ApiController]
[Route("api/[controller]")]
public class AutoCodesController : ControllerBase
{
    private readonly AutoCodeService _autoCodeService;
    private readonly ILogger<AutoCodesController> _logger;

    public AutoCodesController(AutoCodeService autoCodeService, ILogger<AutoCodesController> logger)
    {
        _autoCodeService = autoCodeService;
        _logger = logger;
    }

    /// <summary>
    /// Ottiene tutte le configurazioni AutoCode.
    /// </summary>
    [HttpGet]
    public async Task<ActionResult<List<AutoCodeDto>>> GetAll()
    {
        var configs = await _autoCodeService.GetAllConfigurationsAsync();
        return Ok(configs.Select(ToDto).ToList());
    }

    /// <summary>
    /// Ottiene le configurazioni AutoCode per un modulo specifico.
    /// </summary>
    [HttpGet("module/{moduleCode}")]
    public async Task<ActionResult<List<AutoCodeDto>>> GetByModule(string moduleCode)
    {
        var configs = await _autoCodeService.GetConfigurationsByModuleAsync(moduleCode);
        return Ok(configs.Select(ToDto).ToList());
    }

    /// <summary>
    /// Ottiene una configurazione AutoCode specifica.
    /// </summary>
    [HttpGet("{entityCode}")]
    public async Task<ActionResult<AutoCodeDto>> Get(string entityCode)
    {
        var config = await _autoCodeService.GetConfigurationAsync(entityCode);
        if (config == null)
            return NotFound($"Configurazione per '{entityCode}' non trovata");

        return Ok(ToDto(config));
    }

    /// <summary>
    /// Genera un nuovo codice per un'entità specifica.
    /// </summary>
    [HttpPost("{entityCode}/generate")]
    public async Task<ActionResult<GenerateCodeResponse>> GenerateCode(string entityCode)
    {
        try
        {
            var code = await _autoCodeService.GenerateNextCodeAsync(entityCode);
            if (code == null)
            {
                return BadRequest(new { error = "Generazione automatica disabilitata o configurazione non trovata" });
            }

            return Ok(new GenerateCodeResponse { Code = code, EntityCode = entityCode });
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Errore durante la generazione del codice per {EntityCode}", entityCode);
            return StatusCode(500, new { error = "Errore durante la generazione del codice" });
        }
    }

    /// <summary>
    /// Ottiene un'anteprima del prossimo codice senza incrementare la sequenza.
    /// </summary>
    [HttpGet("{entityCode}/preview")]
    public async Task<ActionResult<GenerateCodeResponse>> PreviewCode(string entityCode)
    {
        var code = await _autoCodeService.PreviewNextCodeAsync(entityCode);
        if (code == null)
        {
            return BadRequest(new { error = "Generazione automatica disabilitata o configurazione non trovata" });
        }

        return Ok(new GenerateCodeResponse { Code = code, EntityCode = entityCode, IsPreview = true });
    }

    /// <summary>
    /// Aggiorna una configurazione AutoCode.
    /// </summary>
    [HttpPut("{id:int}")]
    public async Task<ActionResult<AutoCodeDto>> Update(int id, [FromBody] AutoCodeUpdateDto dto)
    {
        try
        {
            var config = await _autoCodeService.UpdateConfigurationAsync(id, dto);
            return Ok(ToDto(config));
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { error = ex.Message });
        }
        catch (ArgumentException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }

    /// <summary>
    /// Resetta la sequenza per un'entità specifica.
    /// </summary>
    [HttpPost("{entityCode}/reset-sequence")]
    public async Task<ActionResult> ResetSequence(string entityCode, [FromBody] ResetSequenceRequest? request)
    {
        try
        {
            await _autoCodeService.ResetSequenceAsync(entityCode, request?.NewValue ?? 0);
            return Ok(new { message = $"Sequenza resettata per '{entityCode}'" });
        }
        catch (KeyNotFoundException ex)
        {
            return NotFound(new { error = ex.Message });
        }
    }

    /// <summary>
    /// Verifica se un codice è unico per un'entità.
    /// </summary>
    [HttpGet("{entityCode}/check-unique")]
    public async Task<ActionResult<CheckUniqueResponse>> CheckUnique(
        string entityCode,
        [FromQuery] string code,
        [FromQuery] int? excludeId = null)
    {
        var isUnique = await _autoCodeService.IsCodeUniqueAsync(entityCode, code, excludeId);
        return Ok(new CheckUniqueResponse { IsUnique = isUnique, Code = code, EntityCode = entityCode });
    }

    /// <summary>
    /// Ottiene i placeholder disponibili per i pattern.
    /// </summary>
    [HttpGet("placeholders")]
    public ActionResult<List<PlaceholderInfo>> GetPlaceholders()
    {
        var placeholders = new List<PlaceholderInfo>
        {
            new() { Placeholder = "{PREFIX}", Description = "Prefisso configurato", Example = "ART" },
            new() { Placeholder = "{SEQ:n}", Description = "Sequenza numerica con n cifre", Example = "{SEQ:5} → 00001" },
            new() { Placeholder = "{YYYY}", Description = "Anno a 4 cifre", Example = "2025" },
            new() { Placeholder = "{YY}", Description = "Anno a 2 cifre", Example = "25" },
            new() { Placeholder = "{MM}", Description = "Mese a 2 cifre", Example = "11" },
            new() { Placeholder = "{DD}", Description = "Giorno a 2 cifre", Example = "29" },
            new() { Placeholder = "{YEAR}", Description = "Alias per {YYYY}", Example = "2025" },
            new() { Placeholder = "{MONTH}", Description = "Alias per {MM}", Example = "11" },
            new() { Placeholder = "{DAY}", Description = "Alias per {DD}", Example = "29" },
        };

        return Ok(placeholders);
    }

    private static AutoCodeDto ToDto(AutoCode entity)
    {
        return new AutoCodeDto
        {
            Id = entity.Id,
            EntityCode = entity.EntityCode,
            EntityName = entity.EntityName,
            Prefix = entity.Prefix,
            Pattern = entity.Pattern,
            LastSequence = entity.LastSequence,
            ResetSequenceYearly = entity.ResetSequenceYearly,
            ResetSequenceMonthly = entity.ResetSequenceMonthly,
            LastResetYear = entity.LastResetYear,
            LastResetMonth = entity.LastResetMonth,
            IsEnabled = entity.IsEnabled,
            IsReadOnly = entity.IsReadOnly,
            ModuleCode = entity.ModuleCode,
            Description = entity.Description,
            SortOrder = entity.SortOrder,
            ExampleCode = entity.GetExampleCode(),
            CreatedAt = entity.CreatedAt,
            UpdatedAt = entity.UpdatedAt
        };
    }
}

#region DTOs

public class AutoCodeDto
{
    public int Id { get; set; }
    public string EntityCode { get; set; } = string.Empty;
    public string EntityName { get; set; } = string.Empty;
    public string? Prefix { get; set; }
    public string Pattern { get; set; } = string.Empty;
    public long LastSequence { get; set; }
    public bool ResetSequenceYearly { get; set; }
    public bool ResetSequenceMonthly { get; set; }
    public int? LastResetYear { get; set; }
    public int? LastResetMonth { get; set; }
    public bool IsEnabled { get; set; }
    public bool IsReadOnly { get; set; }
    public string? ModuleCode { get; set; }
    public string? Description { get; set; }
    public int SortOrder { get; set; }
    public string ExampleCode { get; set; } = string.Empty;
    public DateTime? CreatedAt { get; set; }
    public DateTime? UpdatedAt { get; set; }
}

public class GenerateCodeResponse
{
    public string Code { get; set; } = string.Empty;
    public string EntityCode { get; set; } = string.Empty;
    public bool IsPreview { get; set; }
}

public class ResetSequenceRequest
{
    public long NewValue { get; set; } = 0;
}

public class CheckUniqueResponse
{
    public bool IsUnique { get; set; }
    public string Code { get; set; } = string.Empty;
    public string EntityCode { get; set; } = string.Empty;
}

public class PlaceholderInfo
{
    public string Placeholder { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    public string Example { get; set; } = string.Empty;
}

#endregion
