using TakeoutSaaS.Domain.Membership.Entities;
using TakeoutSaaS.Domain.Membership.Enums;
using TakeoutSaaS.Domain.Payments.Enums;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Application.App.Members.StoredCard;

/// <summary>
/// 储值卡模块映射与标准化。
/// </summary>
internal static class MemberStoredCardMapping
{
    public static MemberStoredCardPlanStatus ParsePlanStatus(string? value)
    {
        var normalized = (value ?? string.Empty).Trim().ToLowerInvariant();
        return normalized switch
        {
            "enabled" => MemberStoredCardPlanStatus.Enabled,
            "disabled" => MemberStoredCardPlanStatus.Disabled,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "status 参数不合法")
        };
    }

    public static string ToPlanStatusText(MemberStoredCardPlanStatus value)
    {
        return value switch
        {
            MemberStoredCardPlanStatus.Enabled => "enabled",
            MemberStoredCardPlanStatus.Disabled => "disabled",
            _ => "disabled"
        };
    }

    public static PaymentMethod ParsePaymentMethod(string? value)
    {
        var normalized = (value ?? string.Empty).Trim().ToLowerInvariant();
        return normalized switch
        {
            "wechat" => PaymentMethod.WeChatPay,
            "alipay" => PaymentMethod.Alipay,
            "cash" => PaymentMethod.Cash,
            "card" => PaymentMethod.Card,
            "balance" => PaymentMethod.Balance,
            _ => throw new BusinessException(ErrorCodes.BadRequest, "paymentMethod 参数不合法")
        };
    }

    public static string ToPaymentMethodText(PaymentMethod value)
    {
        return value switch
        {
            PaymentMethod.WeChatPay => "wechat",
            PaymentMethod.Alipay => "alipay",
            PaymentMethod.Cash => "cash",
            PaymentMethod.Card => "card",
            PaymentMethod.Balance => "balance",
            _ => "unknown"
        };
    }

    public static string ToPaymentMethodDisplayText(PaymentMethod value)
    {
        return value switch
        {
            PaymentMethod.WeChatPay => "微信支付",
            PaymentMethod.Alipay => "支付宝",
            PaymentMethod.Cash => "现金",
            PaymentMethod.Card => "刷卡",
            PaymentMethod.Balance => "余额",
            _ => "未知"
        };
    }

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

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

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

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

    public static int NormalizeSortOrder(int value)
    {
        if (value < 0 || value > 9999)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "sortOrder 参数不合法");
        }

        return value;
    }

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

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

        return normalized;
    }

    public static string? NormalizeOptionalRemark(string? value)
    {
        var normalized = (value ?? string.Empty).Trim();
        if (normalized.Length == 0)
        {
            return null;
        }

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

        return normalized;
    }

    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 ResolveMemberName(MemberProfile member)
    {
        var nickname = (member.Nickname ?? string.Empty).Trim();
        if (!string.IsNullOrWhiteSpace(nickname))
        {
            return nickname.Length <= 64 ? nickname : nickname[..64];
        }

        var mobile = NormalizePhone(member.Mobile);
        return mobile.Length >= 4 ? $"会员{mobile[^4..]}" : "会员";
    }

    public static string ResolveMemberMobileMasked(MemberProfile member)
    {
        return MaskPhone(NormalizePhone(member.Mobile));
    }

    public static string BuildRechargeRecordNo(DateTime nowUtc)
    {
        var utcNow = NormalizeUtc(nowUtc);
        return $"CZ{utcNow:yyyyMMddHHmmssfff}{Random.Shared.Next(1000, 9999)}";
    }

    private static string NormalizePhone(string? value)
    {
        if (string.IsNullOrWhiteSpace(value))
        {
            return string.Empty;
        }

        var chars = value.Where(char.IsDigit).ToArray();
        return chars.Length == 0 ? string.Empty : new string(chars);
    }

    private static string MaskPhone(string normalizedPhone)
    {
        if (normalizedPhone.Length >= 11)
        {
            return $"{normalizedPhone[..3]}****{normalizedPhone[^4..]}";
        }

        if (normalizedPhone.Length >= 7)
        {
            return $"{normalizedPhone[..3]}***{normalizedPhone[^2..]}";
        }

        return normalizedPhone;
    }
}
