using System.Net.Mail;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Application.App.Finance.Invoice;

/// <summary>
/// 发票模块映射与参数标准化。
/// </summary>
internal static class FinanceInvoiceMapping
{
    public static TenantInvoiceType ParseInvoiceTypeRequired(string? value)
    {
        return ParseInvoiceTypeOptional(value)
               ?? throw new BusinessException(ErrorCodes.BadRequest, "invoiceType 参数不合法");
    }

    public static TenantInvoiceType? ParseInvoiceTypeOptional(string? value)
    {
        var normalized = (value ?? string.Empty).Trim().ToLowerInvariant();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            return null;
        }

        return normalized switch
        {
            "normal" => TenantInvoiceType.Normal,
            "special" => TenantInvoiceType.Special,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "invoiceType 参数不合法")
        };
    }

    public static TenantInvoiceStatus? ParseStatusOptional(string? value)
    {
        var normalized = (value ?? string.Empty).Trim().ToLowerInvariant();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            return null;
        }

        return normalized switch
        {
            "pending" => TenantInvoiceStatus.Pending,
            "issued" => TenantInvoiceStatus.Issued,
            "voided" => TenantInvoiceStatus.Voided,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "status 参数不合法")
        };
    }

    public static string ToInvoiceTypeText(TenantInvoiceType value)
    {
        return value switch
        {
            TenantInvoiceType.Normal => "normal",
            TenantInvoiceType.Special => "special",
            _ => "normal"
        };
    }

    public static string ToInvoiceTypeDisplayText(TenantInvoiceType value)
    {
        return value switch
        {
            TenantInvoiceType.Normal => "普票",
            TenantInvoiceType.Special => "专票",
            _ => "普票"
        };
    }

    public static string ToStatusText(TenantInvoiceStatus value)
    {
        return value switch
        {
            TenantInvoiceStatus.Pending => "pending",
            TenantInvoiceStatus.Issued => "issued",
            TenantInvoiceStatus.Voided => "voided",
            _ => "pending"
        };
    }

    public static string ToStatusDisplayText(TenantInvoiceStatus value)
    {
        return value switch
        {
            TenantInvoiceStatus.Pending => "待开票",
            TenantInvoiceStatus.Issued => "已开票",
            TenantInvoiceStatus.Voided => "已作废",
            _ => "待开票"
        };
    }

    public static string NormalizeCompanyName(string? value)
    {
        return NormalizeRequiredText(value, "companyName", 128);
    }

    public static string NormalizeApplicantName(string? value)
    {
        return NormalizeRequiredText(value, "applicantName", 64);
    }

    public static string NormalizeOrderNo(string? value)
    {
        return NormalizeRequiredText(value, "orderNo", 32);
    }

    public static string NormalizeTaxpayerNumber(string? value)
    {
        return NormalizeRequiredText(value, "taxpayerNumber", 64);
    }

    public static string? NormalizeOptionalTaxpayerNumber(string? value)
    {
        return NormalizeOptionalText(value, "taxpayerNumber", 64);
    }

    public static string? NormalizeOptionalKeyword(string? value)
    {
        return NormalizeOptionalText(value, "keyword", 64);
    }

    public static string? NormalizeOptionalEmail(string? value)
    {
        var normalized = NormalizeOptionalText(value, "contactEmail", 128);
        if (normalized is null)
        {
            return null;
        }

        try
        {
            _ = new MailAddress(normalized);
            return normalized;
        }
        catch (FormatException)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "contactEmail 参数不合法");
        }
    }

    public static string? NormalizeOptionalPhone(string? value)
    {
        return NormalizeOptionalText(value, "contactPhone", 32);
    }

    public static string? NormalizeOptionalRemark(string? value, string fieldName, int maxLength = 256)
    {
        return NormalizeOptionalText(value, fieldName, maxLength);
    }

    public static string NormalizeVoidReason(string? value)
    {
        return NormalizeRequiredText(value, "voidReason", 256);
    }

    public static decimal NormalizeAmount(decimal value)
    {
        if (value <= 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "amount 参数不合法");
        }

        return decimal.Round(value, 2, MidpointRounding.AwayFromZero);
    }

    public static decimal NormalizeAutoIssueMaxAmount(decimal value)
    {
        if (value <= 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "autoIssueMaxAmount 参数不合法");
        }

        return decimal.Round(value, 2, MidpointRounding.AwayFromZero);
    }

    public static (DateTime? StartUtc, DateTime? EndUtc) NormalizeDateRange(DateTime? startUtc, DateTime? endUtc)
    {
        DateTime? normalizedStart = null;
        DateTime? normalizedEnd = null;

        if (startUtc.HasValue)
        {
            var utcValue = NormalizeUtc(startUtc.Value);
            normalizedStart = new DateTime(utcValue.Year, utcValue.Month, utcValue.Day, 0, 0, 0, DateTimeKind.Utc);
        }

        if (endUtc.HasValue)
        {
            var utcValue = NormalizeUtc(endUtc.Value);
            normalizedEnd = new DateTime(utcValue.Year, utcValue.Month, utcValue.Day, 0, 0, 0, DateTimeKind.Utc)
                .AddDays(1)
                .AddTicks(-1);
        }

        if (normalizedStart.HasValue && normalizedEnd.HasValue && normalizedStart > normalizedEnd)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "开始日期不能晚于结束日期");
        }

        return (normalizedStart, normalizedEnd);
    }

    public static DateTime NormalizeUtc(DateTime value)
    {
        return value.Kind switch
        {
            DateTimeKind.Utc => value,
            DateTimeKind.Local => value.ToUniversalTime(),
            _ => DateTime.SpecifyKind(value, DateTimeKind.Utc)
        };
    }

    public static string BuildInvoiceNo(DateTime nowUtc)
    {
        var utcNow = NormalizeUtc(nowUtc);
        return $"INV{utcNow:yyyyMMddHHmmssfff}{Random.Shared.Next(100, 999)}";
    }

    private static string NormalizeRequiredText(string? value, string fieldName, int maxLength)
    {
        var normalized = (value ?? string.Empty).Trim();
        if (string.IsNullOrWhiteSpace(normalized))
        {
            throw new BusinessException(ErrorCodes.BadRequest, $"{fieldName} 参数不合法");
        }

        if (normalized.Length > maxLength)
        {
            throw new BusinessException(ErrorCodes.BadRequest, $"{fieldName} 长度不能超过 {maxLength}");
        }

        return normalized;
    }

    private static string? NormalizeOptionalText(string? value, string fieldName, int maxLength)
    {
        var normalized = (value ?? string.Empty).Trim();
        if (normalized.Length == 0)
        {
            return null;
        }

        if (normalized.Length > maxLength)
        {
            throw new BusinessException(ErrorCodes.BadRequest, $"{fieldName} 长度不能超过 {maxLength}");
        }

        return normalized;
    }
}
