namespace TaxBaik.Application.Services;

using TaxBaik.Domain.Entities;
using TaxBaik.Domain.Interfaces;

public class CompanyService(ICompanyRepository repository)
{
    public async Task<int> CreateAsync(string companyCode, string companyName, string? contactPerson = null,
        string? phone = null, string? email = null, string? memo = null, CancellationToken ct = default)
    {
        if (string.IsNullOrWhiteSpace(companyCode))
            throw new ValidationException("회사 코드를 입력하세요.");

        if (string.IsNullOrWhiteSpace(companyName))
            throw new ValidationException("회사명을 입력하세요.");

        var existing = await repository.GetByCodeAsync(companyCode.Trim(), ct);
        if (existing != null)
            throw new ValidationException("이미 존재하는 회사 코드입니다.");

        var company = new Company
        {
            CompanyCode = companyCode.Trim(),
            CompanyName = companyName.Trim(),
            ContactPerson = string.IsNullOrWhiteSpace(contactPerson) ? null : contactPerson.Trim(),
            Phone = string.IsNullOrWhiteSpace(phone) ? null : phone.Trim(),
            Email = string.IsNullOrWhiteSpace(email) ? null : email.Trim(),
            Memo = string.IsNullOrWhiteSpace(memo) ? null : memo.Trim(),
            IsActive = true,
            CreatedAt = DateTime.UtcNow,
            UpdatedAt = DateTime.UtcNow
        };

        return await repository.CreateAsync(company, ct);
    }

    public async Task<Company?> GetByIdAsync(int id, CancellationToken ct = default) =>
        await repository.GetByIdAsync(id, ct);

    public async Task<Company?> GetByCodeAsync(string code, CancellationToken ct = default) =>
        await repository.GetByCodeAsync(code, ct);

    public async Task<IEnumerable<Company>> GetAllActiveAsync(CancellationToken ct = default) =>
        await repository.GetAllActiveAsync(ct);

    public async Task<(IEnumerable<Company>, int)> GetPagedAsync(int page, int pageSize, CancellationToken ct = default)
    {
        var (items, total) = await repository.GetPagedAsync(NormalizePage(page), NormalizePageSize(pageSize), ct);
        return (items, total);
    }

    public async Task UpdateAsync(int id, string companyCode, string companyName, string? contactPerson = null,
        string? phone = null, string? email = null, string? memo = null, bool isActive = true, CancellationToken ct = default)
    {
        if (string.IsNullOrWhiteSpace(companyCode))
            throw new ValidationException("회사 코드를 입력하세요.");

        if (string.IsNullOrWhiteSpace(companyName))
            throw new ValidationException("회사명을 입력하세요.");

        var company = await repository.GetByIdAsync(id, ct);
        if (company == null)
            throw new ValidationException("회사를 찾을 수 없습니다.");

        var existing = await repository.GetByCodeAsync(companyCode.Trim(), ct);
        if (existing != null && existing.Id != id)
            throw new ValidationException("이미 존재하는 회사 코드입니다.");

        company.CompanyCode = companyCode.Trim();
        company.CompanyName = companyName.Trim();
        company.ContactPerson = string.IsNullOrWhiteSpace(contactPerson) ? null : contactPerson.Trim();
        company.Phone = string.IsNullOrWhiteSpace(phone) ? null : phone.Trim();
        company.Email = string.IsNullOrWhiteSpace(email) ? null : email.Trim();
        company.Memo = string.IsNullOrWhiteSpace(memo) ? null : memo.Trim();
        company.IsActive = isActive;
        company.UpdatedAt = DateTime.UtcNow;

        await repository.UpdateAsync(company, ct);
    }

    public async Task DeleteAsync(int id, CancellationToken ct = default)
    {
        var company = await repository.GetByIdAsync(id, ct);
        if (company == null)
            throw new ValidationException("회사를 찾을 수 없습니다.");

        if (company.CompanyCode == "DEFAULT")
            throw new ValidationException("기본 회사는 삭제할 수 없습니다.");

        await repository.DeleteAsync(id, ct);
    }

    private static int NormalizePage(int page) => Math.Max(1, page);
    private static int NormalizePageSize(int pageSize) => Math.Clamp(pageSize, 1, 100);
}
