using FastEndpoints;
using TaxBaik.Application.Services;
using TaxBaik.Domain.Entities;
using CommonCodeEntity = TaxBaik.Domain.Entities.CommonCode;

namespace TaxBaik.Web.Endpoints.CommonCode;

// DTOs
public class CommonCodeResponse
{
    public List<object> Data { get; set; } = [];
}

public class CommonCodeSingleResponse
{
    public object Data { get; set; } = null!;
}

public class GroupResponse
{
    public List<string> Data { get; set; } = [];
}

public class UpsertCommonCodeRequest
{
    public string? CodeGroup { get; set; }
    public string? CodeValue { get; set; }
    public string? CodeName { get; set; }
    public int? SortOrder { get; set; }
    public bool IsActive { get; set; } = true;
}

public class UpsertCommonCodeResponse
{
    public object Data { get; set; } = null!;
}

// Endpoints
public class GetAllActiveEndpoint : Endpoint<EmptyRequest, CommonCodeResponse>
{
    private readonly CommonCodeService _service;
    public GetAllActiveEndpoint(CommonCodeService service) => _service = service;

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

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        try
        {
            var codes = await _service.GetAllActiveAsync();
            await SendAsync(new CommonCodeResponse { Data = codes.Cast<object>().ToList() }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("공통코드 조회 실패", statusCode: 500);
        }
    }
}

public class GetByGroupEndpoint : Endpoint<EmptyRequest, CommonCodeResponse>
{
    private readonly CommonCodeService _service;
    public GetByGroupEndpoint(CommonCodeService service) => _service = service;

    public override void Configure()
    {
        Get("/api/commoncode/group/{group}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        var group = Route<string>("group");
        try
        {
            if (string.IsNullOrWhiteSpace(group))
                ThrowError("그룹 코드가 필요합니다.", statusCode: 400);
            var codes = await _service.GetByGroupAsync(group);
            await SendAsync(new CommonCodeResponse { Data = codes.Cast<object>().ToList() }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("그룹별 공통코드 조회 실패", statusCode: 500);
        }
    }
}

public class GetGroupsEndpoint : Endpoint<EmptyRequest, GroupResponse>
{
    private readonly CommonCodeService _service;
    public GetGroupsEndpoint(CommonCodeService service) => _service = service;

    public override void Configure()
    {
        Get("/api/commoncode/groups");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        try
        {
            var groups = await _service.GetAllGroupsAsync();
            await SendAsync(new GroupResponse { Data = groups.ToList() }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("공통코드 그룹 조회 실패", statusCode: 500);
        }
    }
}

public class GetByGroupAndValueEndpoint : Endpoint<EmptyRequest, CommonCodeSingleResponse>
{
    private readonly CommonCodeService _service;
    public GetByGroupAndValueEndpoint(CommonCodeService service) => _service = service;

    public override void Configure()
    {
        Get("/api/commoncode/{group}/{value}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        var group = Route<string>("group");
        var value = Route<string>("value");
        try
        {
            if (string.IsNullOrWhiteSpace(group) || string.IsNullOrWhiteSpace(value))
                ThrowError("그룹 코드와 값이 필요합니다.", statusCode: 400);
            var code = await _service.GetAsync(group, value);
            if (code == null)
                ThrowError("공통코드를 찾을 수 없습니다.", statusCode: 404);
            await SendAsync(new CommonCodeSingleResponse { Data = code }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("공통코드 조회 실패", statusCode: 500);
        }
    }
}

public class UpsertEndpoint : Endpoint<UpsertCommonCodeRequest, UpsertCommonCodeResponse>
{
    private readonly CommonCodeService _service;
    public UpsertEndpoint(CommonCodeService service) => _service = service;

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

    public override async Task HandleAsync(UpsertCommonCodeRequest request, CancellationToken ct)
    {
        try
        {
            if (string.IsNullOrWhiteSpace(request.CodeGroup) || string.IsNullOrWhiteSpace(request.CodeValue) || string.IsNullOrWhiteSpace(request.CodeName))
                ThrowError("코드 그룹, 값, 이름은 필수입니다.");

            if (request.CodeGroup.Any(char.IsWhiteSpace))
                ThrowError("code_group에는 공백을 사용할 수 없습니다.");

            if (request.CodeValue.Contains(' '))
                ThrowError("code_value에는 공백을 사용할 수 없습니다.");

            var code = new CommonCodeEntity
            {
                CodeGroup = request.CodeGroup,
                CodeValue = request.CodeValue,
                CodeName = request.CodeName,
                SortOrder = request.SortOrder ?? 0,
                IsActive = request.IsActive
            };

            await _service.UpsertAsync(code);
            await SendAsync(new UpsertCommonCodeResponse { Data = code }, 200, cancellation: ct);
        }
        catch
        {
            ThrowError("공통코드 저장 실패");
        }
    }
}

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

    public override void Configure()
    {
        Delete("/api/commoncode/{group}/{value}");
        Policies("Bearer");
    }

    public override async Task HandleAsync(EmptyRequest _, CancellationToken ct)
    {
        var group = Route<string>("group");
        var value = Route<string>("value");
        try
        {
            if (string.IsNullOrWhiteSpace(group) || string.IsNullOrWhiteSpace(value))
                ThrowError("그룹 코드와 값이 필요합니다.", statusCode: 400);
            await _service.DeleteAsync(group, value);
            await SendNoContentAsync(ct);
        }
        catch
        {
            ThrowError("공통코드 삭제 실패");
        }
    }
}
