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

namespace Apollinare.API.Modules.Warehouse.Controllers;

/// <summary>
/// Controller per la gestione dei magazzini
/// </summary>
[ApiController]
[Route("api/warehouse/locations")]
public class WarehouseLocationsController : ControllerBase
{
    private readonly IWarehouseService _warehouseService;
    private readonly ILogger<WarehouseLocationsController> _logger;

    public WarehouseLocationsController(
        IWarehouseService warehouseService,
        ILogger<WarehouseLocationsController> logger)
    {
        _warehouseService = warehouseService;
        _logger = logger;
    }

    /// <summary>
    /// Ottiene la lista dei magazzini
    /// </summary>
    [HttpGet]
    public async Task<ActionResult<List<WarehouseLocationDto>>> GetWarehouses([FromQuery] bool includeInactive = false)
    {
        var warehouses = await _warehouseService.GetWarehousesAsync(includeInactive);
        return Ok(warehouses.Select(MapToDto));
    }

    /// <summary>
    /// Ottiene un magazzino per ID
    /// </summary>
    [HttpGet("{id}")]
    public async Task<ActionResult<WarehouseLocationDto>> GetWarehouse(int id)
    {
        var warehouse = await _warehouseService.GetWarehouseByIdAsync(id);
        if (warehouse == null)
            return NotFound();

        return Ok(MapToDto(warehouse));
    }

    /// <summary>
    /// Ottiene il magazzino predefinito
    /// </summary>
    [HttpGet("default")]
    public async Task<ActionResult<WarehouseLocationDto>> GetDefaultWarehouse()
    {
        var warehouse = await _warehouseService.GetDefaultWarehouseAsync();
        if (warehouse == null)
            return NotFound(new { error = "Nessun magazzino predefinito configurato" });

        return Ok(MapToDto(warehouse));
    }

    /// <summary>
    /// Crea un nuovo magazzino
    /// </summary>
    [HttpPost]
    public async Task<ActionResult<WarehouseLocationDto>> CreateWarehouse([FromBody] CreateWarehouseDto dto)
    {
        try
        {
            var warehouse = MapFromDto(dto);
            var created = await _warehouseService.CreateWarehouseAsync(warehouse);
            return CreatedAtAction(nameof(GetWarehouse), new { id = created.Id }, MapToDto(created));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }

    /// <summary>
    /// Aggiorna un magazzino esistente
    /// </summary>
    [HttpPut("{id}")]
    public async Task<ActionResult<WarehouseLocationDto>> UpdateWarehouse(int id, [FromBody] UpdateWarehouseDto dto)
    {
        try
        {
            var existing = await _warehouseService.GetWarehouseByIdAsync(id);
            if (existing == null)
                return NotFound();

            UpdateFromDto(existing, dto);
            var updated = await _warehouseService.UpdateWarehouseAsync(existing);
            return Ok(MapToDto(updated));
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }

    /// <summary>
    /// Elimina un magazzino
    /// </summary>
    [HttpDelete("{id}")]
    public async Task<ActionResult> DeleteWarehouse(int id)
    {
        try
        {
            await _warehouseService.DeleteWarehouseAsync(id);
            return NoContent();
        }
        catch (ArgumentException ex)
        {
            return NotFound(new { error = ex.Message });
        }
        catch (InvalidOperationException ex)
        {
            return BadRequest(new { error = ex.Message });
        }
    }

    /// <summary>
    /// Imposta un magazzino come predefinito
    /// </summary>
    [HttpPut("{id}/set-default")]
    public async Task<ActionResult> SetDefaultWarehouse(int id)
    {
        try
        {
            await _warehouseService.SetDefaultWarehouseAsync(id);
            return Ok();
        }
        catch (ArgumentException ex)
        {
            return NotFound(new { error = ex.Message });
        }
    }

    #region DTOs

    public record WarehouseLocationDto(
        int Id,
        string Code,
        string Name,
        string? Description,
        string? Address,
        string? City,
        string? Province,
        string? PostalCode,
        string? Country,
        WarehouseType Type,
        bool IsDefault,
        bool IsActive,
        int SortOrder,
        string? Notes,
        DateTime? CreatedAt,
        DateTime? UpdatedAt
    );

    public record CreateWarehouseDto(
        string Code,
        string Name,
        string? Description,
        string? Address,
        string? City,
        string? Province,
        string? PostalCode,
        string? Country,
        WarehouseType Type,
        bool IsDefault,
        int SortOrder,
        string? Notes
    );

    public record UpdateWarehouseDto(
        string Code,
        string Name,
        string? Description,
        string? Address,
        string? City,
        string? Province,
        string? PostalCode,
        string? Country,
        WarehouseType Type,
        bool IsDefault,
        bool IsActive,
        int SortOrder,
        string? Notes
    );

    #endregion

    #region Mapping

    private static WarehouseLocationDto MapToDto(WarehouseLocation warehouse) => new(
        warehouse.Id,
        warehouse.Code,
        warehouse.Name,
        warehouse.Description,
        warehouse.Address,
        warehouse.City,
        warehouse.Province,
        warehouse.PostalCode,
        warehouse.Country,
        warehouse.Type,
        warehouse.IsDefault,
        warehouse.IsActive,
        warehouse.SortOrder,
        warehouse.Notes,
        warehouse.CreatedAt,
        warehouse.UpdatedAt
    );

    private static WarehouseLocation MapFromDto(CreateWarehouseDto dto) => new()
    {
        Code = dto.Code,
        Name = dto.Name,
        Description = dto.Description,
        Address = dto.Address,
        City = dto.City,
        Province = dto.Province,
        PostalCode = dto.PostalCode,
        Country = dto.Country ?? "Italia",
        Type = dto.Type,
        IsDefault = dto.IsDefault,
        SortOrder = dto.SortOrder,
        Notes = dto.Notes,
        IsActive = true
    };

    private static void UpdateFromDto(WarehouseLocation warehouse, UpdateWarehouseDto dto)
    {
        warehouse.Code = dto.Code;
        warehouse.Name = dto.Name;
        warehouse.Description = dto.Description;
        warehouse.Address = dto.Address;
        warehouse.City = dto.City;
        warehouse.Province = dto.Province;
        warehouse.PostalCode = dto.PostalCode;
        warehouse.Country = dto.Country;
        warehouse.Type = dto.Type;
        warehouse.IsDefault = dto.IsDefault;
        warehouse.IsActive = dto.IsActive;
        warehouse.SortOrder = dto.SortOrder;
        warehouse.Notes = dto.Notes;
    }

    #endregion
}
