using Apollinare.API.Services;
using Apollinare.Domain.Entities;
using Apollinare.Infrastructure.Data;
using Microsoft.AspNetCore.Mvc;
using Microsoft.EntityFrameworkCore;

namespace Apollinare.API.Controllers;

[ApiController]
[Route("api/eventi/{eventoId}/costi")]
public class EventiCostiController : ControllerBase
{
    private readonly AppollinareDbContext _context;
    private readonly EventoCostiService _costiService;

    public EventiCostiController(AppollinareDbContext context, EventoCostiService costiService)
    {
        _context = context;
        _costiService = costiService;
    }

    /// <summary>
    /// Ottiene il riepilogo completo dei costi per un evento
    /// </summary>
    [HttpGet("riepilogo")]
    public async Task<ActionResult<EventoCostiRiepilogo>> GetRiepilogoCosti(int eventoId)
    {
        try
        {
            var riepilogo = await _costiService.CalcolaCostiEvento(eventoId);
            return Ok(riepilogo);
        }
        catch (ArgumentException ex)
        {
            return NotFound(ex.Message);
        }
    }

    /// <summary>
    /// Ricalcola gli acconti automatici per l'evento
    /// </summary>
    [HttpPost("ricalcola-acconti")]
    public async Task<ActionResult<EventoCostiRiepilogo>> RicalcolaAcconti(int eventoId)
    {
        try
        {
            await _costiService.RicalcolaAcconti(eventoId);
            var riepilogo = await _costiService.CalcolaCostiEvento(eventoId);
            return Ok(riepilogo);
        }
        catch (ArgumentException ex)
        {
            return NotFound(ex.Message);
        }
    }

    // === ALTRI COSTI ===

    /// <summary>
    /// Ottiene tutti gli altri costi di un evento
    /// </summary>
    [HttpGet("altri")]
    public async Task<ActionResult<IEnumerable<EventoAltroCosto>>> GetAltriCosti(int eventoId)
    {
        var costi = await _context.Set<EventoAltroCosto>()
            .Where(c => c.EventoId == eventoId)
            .OrderBy(c => c.Ordine)
            .ToListAsync();
        return Ok(costi);
    }

    /// <summary>
    /// Aggiunge un nuovo costo all'evento
    /// </summary>
    [HttpPost("altri")]
    public async Task<ActionResult<EventoAltroCosto>> AddAltroCosto(int eventoId, [FromBody] EventoAltroCostoDto dto)
    {
        var evento = await _context.Eventi.FindAsync(eventoId);
        if (evento == null)
            return NotFound($"Evento {eventoId} non trovato");

        var maxOrdine = await _context.Set<EventoAltroCosto>()
            .Where(c => c.EventoId == eventoId)
            .MaxAsync(c => (int?)c.Ordine) ?? 0;

        var costo = new EventoAltroCosto
        {
            EventoId = eventoId,
            Descrizione = dto.Descrizione,
            CostoUnitario = dto.CostoUnitario,
            Quantita = dto.Quantita ?? 1,
            Ordine = dto.Ordine ?? maxOrdine + 10,
            ApplicaIva = dto.ApplicaIva ?? true,
            AliquotaIva = dto.AliquotaIva ?? 10
        };

        _context.Set<EventoAltroCosto>().Add(costo);
        await _context.SaveChangesAsync();

        return CreatedAtAction(nameof(GetAltriCosti), new { eventoId }, costo);
    }

    /// <summary>
    /// Aggiorna un costo esistente
    /// </summary>
    [HttpPut("altri/{id}")]
    public async Task<ActionResult<EventoAltroCosto>> UpdateAltroCosto(int eventoId, int id, [FromBody] EventoAltroCostoDto dto)
    {
        var costo = await _context.Set<EventoAltroCosto>()
            .FirstOrDefaultAsync(c => c.Id == id && c.EventoId == eventoId);

        if (costo == null)
            return NotFound();

        costo.Descrizione = dto.Descrizione;
        costo.CostoUnitario = dto.CostoUnitario;
        costo.Quantita = dto.Quantita ?? costo.Quantita;
        costo.Ordine = dto.Ordine ?? costo.Ordine;
        costo.ApplicaIva = dto.ApplicaIva ?? costo.ApplicaIva;
        costo.AliquotaIva = dto.AliquotaIva ?? costo.AliquotaIva;

        await _context.SaveChangesAsync();
        return Ok(costo);
    }

    /// <summary>
    /// Elimina un costo
    /// </summary>
    [HttpDelete("altri/{id}")]
    public async Task<ActionResult> DeleteAltroCosto(int eventoId, int id)
    {
        var costo = await _context.Set<EventoAltroCosto>()
            .FirstOrDefaultAsync(c => c.Id == id && c.EventoId == eventoId);

        if (costo == null)
            return NotFound();

        _context.Set<EventoAltroCosto>().Remove(costo);
        await _context.SaveChangesAsync();
        return NoContent();
    }

    /// <summary>
    /// Riordina gli altri costi
    /// </summary>
    [HttpPost("altri/riordina")]
    public async Task<ActionResult> RiordinaAltriCosti(int eventoId, [FromBody] List<int> ordineIds)
    {
        var costi = await _context.Set<EventoAltroCosto>()
            .Where(c => c.EventoId == eventoId)
            .ToListAsync();

        for (int i = 0; i < ordineIds.Count; i++)
        {
            var costo = costi.FirstOrDefault(c => c.Id == ordineIds[i]);
            if (costo != null)
            {
                costo.Ordine = (i + 1) * 10;
            }
        }

        await _context.SaveChangesAsync();
        return Ok();
    }

    // === ACCONTI ===

    /// <summary>
    /// Ottiene tutti gli acconti di un evento
    /// </summary>
    [HttpGet("acconti")]
    public async Task<ActionResult<IEnumerable<EventoAcconto>>> GetAcconti(int eventoId)
    {
        var acconti = await _context.Set<EventoAcconto>()
            .Where(a => a.EventoId == eventoId)
            .OrderBy(a => a.Ordine)
            .ToListAsync();
        return Ok(acconti);
    }

    /// <summary>
    /// Aggiunge un nuovo acconto all'evento
    /// </summary>
    [HttpPost("acconti")]
    public async Task<ActionResult<EventoAcconto>> AddAcconto(int eventoId, [FromBody] EventoAccontoDto dto)
    {
        var evento = await _context.Eventi.FindAsync(eventoId);
        if (evento == null)
            return NotFound($"Evento {eventoId} non trovato");

        var maxOrdine = await _context.Set<EventoAcconto>()
            .Where(a => a.EventoId == eventoId)
            .MaxAsync(a => (int?)a.Ordine) ?? 0;

        var acconto = new EventoAcconto
        {
            EventoId = eventoId,
            Descrizione = dto.Descrizione,
            Importo = dto.Importo,
            DataPagamento = dto.DataPagamento,
            AConferma = dto.AConferma ?? false,
            Ordine = dto.Ordine ?? maxOrdine + 10,
            MetodoPagamento = dto.MetodoPagamento,
            Note = dto.Note
        };

        _context.Set<EventoAcconto>().Add(acconto);
        await _context.SaveChangesAsync();

        return CreatedAtAction(nameof(GetAcconti), new { eventoId }, acconto);
    }

    /// <summary>
    /// Aggiorna un acconto esistente
    /// </summary>
    [HttpPut("acconti/{id}")]
    public async Task<ActionResult<EventoAcconto>> UpdateAcconto(int eventoId, int id, [FromBody] EventoAccontoDto dto)
    {
        var acconto = await _context.Set<EventoAcconto>()
            .FirstOrDefaultAsync(a => a.Id == id && a.EventoId == eventoId);

        if (acconto == null)
            return NotFound();

        acconto.Descrizione = dto.Descrizione;
        acconto.Importo = dto.Importo;
        acconto.DataPagamento = dto.DataPagamento;
        acconto.AConferma = dto.AConferma ?? acconto.AConferma;
        acconto.Ordine = dto.Ordine ?? acconto.Ordine;
        acconto.MetodoPagamento = dto.MetodoPagamento;
        acconto.Note = dto.Note;

        await _context.SaveChangesAsync();
        return Ok(acconto);
    }

    /// <summary>
    /// Segna un acconto come pagato
    /// </summary>
    [HttpPost("acconti/{id}/paga")]
    public async Task<ActionResult<EventoAcconto>> PagaAcconto(int eventoId, int id, [FromBody] PagaAccontoDto dto)
    {
        var acconto = await _context.Set<EventoAcconto>()
            .FirstOrDefaultAsync(a => a.Id == id && a.EventoId == eventoId);

        if (acconto == null)
            return NotFound();

        acconto.DataPagamento = dto.DataPagamento ?? DateTime.Today;
        acconto.MetodoPagamento = dto.MetodoPagamento;
        acconto.Note = dto.Note;

        await _context.SaveChangesAsync();
        return Ok(acconto);
    }

    /// <summary>
    /// Elimina un acconto
    /// </summary>
    [HttpDelete("acconti/{id}")]
    public async Task<ActionResult> DeleteAcconto(int eventoId, int id)
    {
        var acconto = await _context.Set<EventoAcconto>()
            .FirstOrDefaultAsync(a => a.Id == id && a.EventoId == eventoId);

        if (acconto == null)
            return NotFound();

        _context.Set<EventoAcconto>().Remove(acconto);
        await _context.SaveChangesAsync();
        return NoContent();
    }
}

// DTOs
public class EventoAltroCostoDto
{
    public string Descrizione { get; set; } = string.Empty;
    public decimal CostoUnitario { get; set; }
    public decimal? Quantita { get; set; }
    public int? Ordine { get; set; }
    public bool? ApplicaIva { get; set; }
    public decimal? AliquotaIva { get; set; }
}

public class EventoAccontoDto
{
    public string? Descrizione { get; set; }
    public decimal Importo { get; set; }
    public DateTime? DataPagamento { get; set; }
    public bool? AConferma { get; set; }
    public int? Ordine { get; set; }
    public string? MetodoPagamento { get; set; }
    public string? Note { get; set; }
}

public class PagaAccontoDto
{
    public DateTime? DataPagamento { get; set; }
    public string? MetodoPagamento { get; set; }
    public string? Note { get; set; }
}
