using FastEndpoints;
using TaxBaik.Application.Services;
using TaxBaik.Domain.Entities;
using TaxFilingEntity = TaxBaik.Domain.Entities.TaxFiling;

namespace TaxBaik.Web.Endpoints.TaxFiling;

// DTOs
public class GetUpcomingQuery
{
    public int DaysAhead { get; set; } = 30;
}

public class CreateTaxFilingRequest
{
    public int ClientId { get; set; }
    public string? FilingType { get; set; }
    public DateTime DueDate { get; set; }
    public string? Status { get; set; }
    public string? Memo { get; set; }
}

public class UpdateTaxFilingRequest
{
    public string? FilingType { get; set; }
    public DateTime? DueDate { get; set; }
    public string? Status { get; set; }
    public string? Memo { get; set; }
}

public class TaxFilingListResponse
{
    public List<object> Data { get; set; } = [];
}

public class TaxFilingResponse
{
    public int Id { get; set; }
}

public class TaxFilingUpdateResponse
{
    public string Message { get; set; } = string.Empty;
}

// Endpoints
public class GetUpcomingEndpoint : Endpoint<GetUpcomingQuery, TaxFilingListResponse>
{
    private readonly TaxFilingService _service;
    public GetUpcomingEndpoint(TaxFilingService service) => _service = service;

    public override void Configure()
    {
        Get("/api/taxfiling/upcoming");
        Policies("Bearer");
    }

    public override async Task HandleAsync(GetUpcomingQuery request, CancellationToken ct)
    {
        try
        {
            var filings = await _service.GetUpcomingAsync(request.DaysAhead);
            await SendAsync(new TaxFilingListResponse { Data = filings.Cast<object>().ToList() }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("예정 신고 조회 실패", statusCode: 500);
        }
    }
}

public class GetByClientIdEndpoint : Endpoint<EmptyRequest, TaxFilingListResponse>
{
    private readonly TaxFilingService _service;
    public GetByClientIdEndpoint(TaxFilingService service) => _service = service;

    public override void Configure()
    {
        Get("/api/taxfiling/client/{clientId}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        var clientId = Route<int>("clientId");
        try
        {
            var filings = await _service.GetByClientIdAsync(clientId);
            await SendAsync(new TaxFilingListResponse { Data = filings.Cast<object>().ToList() }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("고객별 신고 조회 실패", statusCode: 500);
        }
    }
}

public class GetByIdEndpoint : Endpoint<EmptyRequest, object>
{
    private readonly TaxFilingService _service;
    public GetByIdEndpoint(TaxFilingService service) => _service = service;

    public override void Configure()
    {
        Get("/api/taxfiling/{id}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        var id = Route<int>("id");
        try
        {
            var filing = await _service.GetByIdAsync(id);
            if (filing == null)
                ThrowError("신고 일정을 찾을 수 없습니다.", statusCode: 404);
            await SendAsync(filing, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("신고 상세 조회 실패", statusCode: 500);
        }
    }
}

public class CreateEndpoint : Endpoint<CreateTaxFilingRequest, TaxFilingResponse>
{
    private readonly TaxFilingService _service;
    public CreateEndpoint(TaxFilingService service) => _service = service;

    public override void Configure()
    {
        Post("/api/taxfiling");
        Policies("Bearer");
    }

    public override async Task HandleAsync(CreateTaxFilingRequest request, CancellationToken ct)
    {
        try
        {
            var filing = new TaxFilingEntity
            {
                ClientId = request.ClientId,
                FilingType = request.FilingType ?? string.Empty,
                DueDate = request.DueDate,
                Status = request.Status ?? "pending",
                Memo = request.Memo
            };
            var filingId = await _service.CreateAsync(filing);
            var result = await _service.GetByIdAsync(filingId);
            await SendAsync(new TaxFilingResponse { Id = filingId }, 201, cancellation: ct);
        }
        catch
        {
            ThrowError("신고 생성 실패");
        }
    }
}

public class UpdateEndpoint : Endpoint<UpdateTaxFilingRequest, TaxFilingUpdateResponse>
{
    private readonly TaxFilingService _service;
    public UpdateEndpoint(TaxFilingService service) => _service = service;

    public override void Configure()
    {
        Put("/api/taxfiling/{id}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(UpdateTaxFilingRequest request, CancellationToken ct)
    {
        var id = Route<int>("id");
        try
        {
            var filing = new TaxFilingEntity
            {
                Id = id,
                FilingType = request.FilingType ?? string.Empty,
                DueDate = request.DueDate ?? DateTime.Now,
                Status = request.Status ?? "pending",
                Memo = request.Memo
            };
            await _service.UpdateAsync(filing);
            var result = await _service.GetByIdAsync(id);
            if (result == null)
                ThrowError("신고 일정을 찾을 수 없습니다.", statusCode: 404);
            await SendAsync(new TaxFilingUpdateResponse { Message = "신고 일정이 수정되었습니다." }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("신고 수정 실패");
        }
    }
}

public class DeleteEndpoint : Endpoint<EmptyRequest, EmptyResponse>
{
    private readonly TaxFilingService _service;
    public DeleteEndpoint(TaxFilingService service) => _service = service;

    public override void Configure()
    {
        Delete("/api/taxfiling/{id}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        var id = Route<int>("id");
        try
        {
            await _service.DeleteAsync(id);
            await SendNoContentAsync(ct);
        }
        catch
        {
            ThrowError("신고 삭제 실패");
        }
    }
}
