using System.Text;
using MediatR;
using TakeoutSaaS.Application.App.Coupons.PunchCard.Dto;
using TakeoutSaaS.Application.App.Coupons.PunchCard.Queries;
using TakeoutSaaS.Domain.Coupons.Repositories;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Coupons.PunchCard.Handlers;

/// <summary>
/// 导出次卡使用记录处理器。
/// </summary>
public sealed class ExportPunchCardUsageRecordCsvQueryHandler(
    IPunchCardRepository repository,
    ITenantProvider tenantProvider)
    : IRequestHandler<ExportPunchCardUsageRecordCsvQuery, PunchCardUsageRecordExportDto>
{
    /// <inheritdoc />
    public async Task<PunchCardUsageRecordExportDto> Handle(
        ExportPunchCardUsageRecordCsvQuery request,
        CancellationToken cancellationToken)
    {
        var tenantId = tenantProvider.GetCurrentTenantId();
        var normalizedStatus = PunchCardMapping.ParseUsageStatusFilter(request.Status);

        var records = await repository.ListUsageRecordsForExportAsync(
            tenantId,
            request.StoreId,
            request.TemplateId,
            request.Keyword,
            normalizedStatus,
            cancellationToken);

        if (records.Count == 0)
        {
            return new PunchCardUsageRecordExportDto
            {
                FileName = $"次卡使用记录_{DateTime.UtcNow:yyyyMMddHHmmss}.csv",
                FileContentBase64 = Convert.ToBase64String(Encoding.UTF8.GetBytes("\uFEFF使用单号,会员,手机号,次卡,兑换商品,使用时间,剩余次数,总次数,状态\n")),
                TotalCount = 0
            };
        }

        var instanceIds = records.Select(item => item.PunchCardInstanceId).Distinct().ToList();
        var instances = await repository.GetInstancesByIdsAsync(
            tenantId,
            request.StoreId,
            instanceIds,
            cancellationToken);

        var instanceMap = instances.ToDictionary(item => item.Id, item => item);

        var templateIds = records.Select(item => item.PunchCardTemplateId)
            .Concat(instances.Select(item => item.PunchCardTemplateId))
            .Distinct()
            .ToList();

        var templates = await repository.GetTemplatesByIdsAsync(
            tenantId,
            request.StoreId,
            templateIds,
            cancellationToken);

        var templateMap = templates.ToDictionary(item => item.Id, item => item);

        var csv = BuildCsv(records, instanceMap, templateMap);
        var bytes = Encoding.UTF8.GetBytes($"\uFEFF{csv}");

        return new PunchCardUsageRecordExportDto
        {
            FileName = $"次卡使用记录_{DateTime.UtcNow:yyyyMMddHHmmss}.csv",
            FileContentBase64 = Convert.ToBase64String(bytes),
            TotalCount = records.Count
        };
    }

    private static string BuildCsv(
        IReadOnlyCollection<Domain.Coupons.Entities.PunchCardUsageRecord> records,
        IReadOnlyDictionary<long, Domain.Coupons.Entities.PunchCardInstance> instanceMap,
        IReadOnlyDictionary<long, Domain.Coupons.Entities.PunchCardTemplate> templateMap)
    {
        var lines = new List<string>
        {
            "使用单号,会员,手机号,次卡,兑换商品,使用时间,剩余次数,总次数,状态"
        };

        var nowUtc = DateTime.UtcNow;
        foreach (var record in records)
        {
            instanceMap.TryGetValue(record.PunchCardInstanceId, out var instance);
            templateMap.TryGetValue(record.PunchCardTemplateId, out var template);

            var dto = PunchCardDtoFactory.ToUsageRecordDto(record, instance, template, nowUtc);
            var statusText = ResolveStatusText(dto.DisplayStatus);

            lines.Add(string.Join(",",
                Escape(dto.RecordNo),
                Escape(dto.MemberName),
                Escape(dto.MemberPhoneMasked),
                Escape(dto.PunchCardName),
                Escape(dto.ProductName),
                Escape(dto.UsedAt.ToString("yyyy-MM-dd HH:mm:ss")),
                dto.RemainingTimesAfterUse,
                dto.TotalTimes,
                Escape(statusText)));
        }

        return string.Join('\n', lines);
    }

    private static string ResolveStatusText(string value)
    {
        return value switch
        {
            "normal" => "正常使用",
            "almost_used_up" => "即将用完",
            "used_up" => "已用完",
            "expired" => "已过期",
            _ => "正常使用"
        };
    }

    private static string Escape(string value)
    {
        var text = value.Replace("\"", "\"\"");
        return $"\"{text}\"";
    }
}
