using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using TaxBaik.Domain.Entities;
using TaxBaik.Domain.Interfaces;

namespace TaxBaik.Application.Services;

public class CommonCodeService(ICommonCodeRepository commonCodeRepository)
{
    private const int MaxCodeGroupLength = 80;
    private const int MaxCodeValueLength = 120;
    private const int MaxCodeNameLength = 200;

    public async Task<IEnumerable<string>> GetAllGroupsAsync(CancellationToken ct = default)
    {
        return await commonCodeRepository.GetAllGroupsAsync(ct);
    }

    public async Task<IEnumerable<CommonCode>> GetByGroupAsync(string codeGroup, CancellationToken ct = default)
    {
        return await commonCodeRepository.GetByGroupAsync(codeGroup, ct);
    }

    public async Task<IEnumerable<CommonCode>> GetAllActiveAsync(CancellationToken ct = default)
    {
        return await commonCodeRepository.GetAllActiveAsync(ct);
    }

    public async Task<CommonCode?> GetAsync(string codeGroup, string codeValue, CancellationToken ct = default)
    {
        return await commonCodeRepository.GetAsync(codeGroup, codeValue, ct);
    }

    public async Task UpsertAsync(CommonCode code, CancellationToken ct = default)
    {
        Normalize(code);
        await commonCodeRepository.UpsertAsync(code, ct);
    }

    public async Task DeleteAsync(string codeGroup, string codeValue, CancellationToken ct = default)
    {
        await commonCodeRepository.DeleteAsync(NormalizeToken(codeGroup, nameof(codeGroup), MaxCodeGroupLength), NormalizeToken(codeValue, nameof(codeValue), MaxCodeValueLength), ct);
    }

    private static void Normalize(CommonCode code)
    {
        code.CodeGroup = NormalizeToken(code.CodeGroup, nameof(code.CodeGroup), MaxCodeGroupLength, disallowWhitespace: true);
        code.CodeValue = NormalizeToken(code.CodeValue, nameof(code.CodeValue), MaxCodeValueLength, disallowWhitespace: true);
        code.CodeName = NormalizeToken(code.CodeName, nameof(code.CodeName), MaxCodeNameLength);
    }

    private static string NormalizeToken(string value, string fieldName, int maxLength, bool disallowWhitespace = false)
    {
        var normalized = (value ?? string.Empty).Trim();
        if (string.IsNullOrWhiteSpace(normalized))
            throw new ValidationException($"{fieldName}은(는) 필수입니다.");

        if (normalized.Length > maxLength)
            throw new ValidationException($"{fieldName}은(는) 최대 {maxLength}자까지 입력할 수 있습니다.");

        if (disallowWhitespace && normalized.Any(char.IsWhiteSpace))
            throw new ValidationException($"{fieldName}에는 공백을 사용할 수 없습니다.");

        return normalized;
    }
}
