using System.ComponentModel.DataAnnotations;
using DoliMiddlewareApi.Dtos;
using DoliMiddlewareApi.Dtos.command;
using DoliMiddlewareApi.Dtos.query;
using DoliMiddlewareApi.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;

namespace DoliMiddlewareApi.Controllers;

[ApiController]
[Route("api/[controller]")]
[Authorize]
public class InvoicesController(InvoiceService invoiceService) : ControllerBase
{
    [HttpGet]
    [ProducesResponseType(typeof(List<InvoiceDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<List<InvoiceDto>>> GetInvoices(
        [FromQuery] int limit = 50,
        [FromQuery] [Range(1, int.MaxValue)] int page = 1,
        [FromQuery] string? status = null,
        [FromQuery] [StringLength(100)] string? search = null)
    {
        var invoices = await invoiceService.GetInvoicesAsync(limit, page, status, search);
        return Ok(invoices);
    }

    [HttpGet("{id:int}")]
    [ProducesResponseType(typeof(InvoiceDetailDto), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<InvoiceDetailDto>> GetInvoice([Range(1, int.MaxValue)] int id)
    {
        var invoice = await invoiceService.GetInvoiceAsync(id);
        return Ok(invoice);
    }

    [HttpPost]
    [ProducesResponseType(typeof(int), StatusCodes.Status201Created)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<int>> CreateInvoice([FromBody] CreateInvoiceDto createInvoiceDto)
    {
        var invoiceId = await invoiceService.CreateInvoiceAsync(createInvoiceDto);
        return CreatedAtAction(nameof(GetInvoice), new { id = invoiceId }, invoiceId);
    }

    [HttpPut("{id:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> UpdateInvoice([Range(1, int.MaxValue)] int id,
        [FromBody] UpdateInvoiceDto updateInvoiceDto)
    {
        await invoiceService.UpdateInvoiceAsync(id, updateInvoiceDto);
        return NoContent();
    }

    [HttpPost("{id:int}/lines")]
    [ProducesResponseType(typeof(string), StatusCodes.Status201Created)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status403Forbidden)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<string>> AddInvoiceLine([Range(1, int.MaxValue)] int id,
        [FromBody] CreateInvoiceLineDto lineDto)
    {
        var result = await invoiceService.AddInvoiceLineAsync(id, lineDto);
        return CreatedAtAction(nameof(GetInvoice), new { id }, result);
    }

    [HttpPatch("{id:int}/status")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> UpdateInvoiceStatus(
        [Range(1, int.MaxValue)] int id,
        [FromBody] UpdateInvoiceStatusDto updateStatusDto)
    {
        await invoiceService.ChangeInvoiceStatusAsync(id, updateStatusDto.Status);
        return NoContent();
    }

    [HttpPost("{id:int}/validate")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status403Forbidden)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> ValidateInvoice([Range(1, int.MaxValue)] int id)
    {
        await invoiceService.ValidateInvoiceAsync(id);
        return NoContent();
    }

    [HttpDelete("{id:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status403Forbidden)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> DeleteInvoice([Range(1, int.MaxValue)] int id)
    {
        await invoiceService.DeleteInvoiceAsync(id);
        return NoContent();
    }

    [HttpDelete("{invoiceId:int}/lines/{lineId:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status403Forbidden)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> DeleteInvoiceLine(
        [Range(1, int.MaxValue)] int invoiceId,
        [Range(1, int.MaxValue)] int lineId)
    {
        await invoiceService.DeleteInvoiceLineAsync(invoiceId, lineId);
        return NoContent();
    }

    [HttpPut("{invoiceId:int}/lines/{lineId:int}")]
    [ProducesResponseType(StatusCodes.Status204NoContent)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status403Forbidden)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<IActionResult> UpdateInvoiceLine(
        [Range(1, int.MaxValue)] int invoiceId,
        [Range(1, int.MaxValue)] int lineId,
        [FromBody] UpdateInvoiceLineDto dto)
    {
        await invoiceService.UpdateInvoiceLineAsync(invoiceId, lineId, dto);
        return NoContent();
    }

    [HttpGet("templates")]
    [ProducesResponseType(typeof(List<InvoiceDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<List<InvoiceDto>>> GetInvoiceTemplates()
    {
        var templates = await invoiceService.GetInvoiceTemplatesAsync();
        return Ok(templates);
    }

    [HttpGet("templates/{id:int}")]
    [ProducesResponseType(typeof(InvoiceDetailDto), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<InvoiceDetailDto>> GetInvoiceTemplate([Range(1, int.MaxValue)] int id)
    {
        var template = await invoiceService.GetInvoiceTemplateAsync(id);
        return Ok(template);
    }

    [HttpGet("{id:int}/payments")]
    [ProducesResponseType(typeof(List<InvoicePaymentDto>), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status404NotFound)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<List<InvoicePaymentDto>>> GetInvoicePayments([Range(1, int.MaxValue)] int id)
    {
        var payments = await invoiceService.GetInvoicePaymentsAsync(id);
        return Ok(payments);
    }

    [HttpPost("{id:int}/payments")]
    [ProducesResponseType(typeof(long), StatusCodes.Status200OK)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status400BadRequest)]
    [ProducesResponseType(typeof(ProblemDetails), StatusCodes.Status401Unauthorized)]
    public async Task<ActionResult<long>> AddPayment(
        [Range(1, int.MaxValue)] int id,
        [FromBody] CreateInvoicePaymentDto dto)
    {
        var paymentId = await invoiceService.AddInvoicePaymentAsync(id, dto);
        return Ok(paymentId);
    }
}