using MediatR;
using System.Text.Json;
using TakeoutSaaS.Application.App.Billings.Commands;
using TakeoutSaaS.Application.App.Billings.Dto;
using TakeoutSaaS.Domain.Tenants.Entities;
using TakeoutSaaS.Domain.Tenants.Enums;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Ids;

namespace TakeoutSaaS.Application.App.Billings.Handlers;

/// <summary>
/// 生成订阅账单命令处理器。
/// </summary>
public sealed class GenerateSubscriptionBillingCommandHandler(
    ISubscriptionRepository subscriptionRepository,
    ITenantBillingRepository billingRepository,
    IIdGenerator idGenerator)
    : IRequestHandler<GenerateSubscriptionBillingCommand, BillingDetailDto>
{
    /// <inheritdoc />
    public async Task<BillingDetailDto> Handle(GenerateSubscriptionBillingCommand request, CancellationToken cancellationToken)
    {
        // 1. 查询订阅详情（含租户/套餐信息）
        var detail = await subscriptionRepository.GetDetailAsync(request.SubscriptionId, cancellationToken);
        if (detail is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "订阅不存在");
        }

        // 2. 校验套餐价格信息
        var subscription = detail.Subscription;
        var package = detail.Package;
        if (package is null)
        {
            throw new BusinessException(ErrorCodes.BusinessError, "订阅未关联有效套餐，无法生成账单");
        }

        // 3. 按订阅周期选择价格（简化规则：优先按年/按月）
        var billingPeriodDays = (subscription.EffectiveTo - subscription.EffectiveFrom).TotalDays;
        var amountDue = billingPeriodDays >= 300
            ? package.YearlyPrice
            : package.MonthlyPrice;

        if (!amountDue.HasValue)
        {
            throw new BusinessException(ErrorCodes.BusinessError, "套餐价格未配置，无法生成账单");
        }

        // 4. 幂等校验：同一周期开始时间仅允许存在一张未取消账单
        var exists = await billingRepository.ExistsNotCancelledByPeriodStartAsync(subscription.TenantId, subscription.EffectiveFrom, cancellationToken);
        if (exists)
        {
            throw new BusinessException(ErrorCodes.Conflict, "该订阅周期的账单已存在");
        }

        // 5. 构建账单实体
        var now = DateTime.UtcNow;
        var statementNo = $"BIL-{now:yyyyMMdd}-{idGenerator.NextId()}";
        var lineItems = new List<BillingLineItemDto>
        {
            new()
            {
                ItemType = "Subscription",
                Description = $"套餐 {package.Name} 订阅费用",
                Quantity = 1,
                UnitPrice = amountDue.Value,
                Amount = amountDue.Value,
                DiscountRate = null
            }
        };

        var billing = new TenantBillingStatement
        {
            TenantId = subscription.TenantId,
            StatementNo = statementNo,
            BillingType = BillingType.Subscription,
            SubscriptionId = subscription.Id,
            PeriodStart = subscription.EffectiveFrom,
            PeriodEnd = subscription.EffectiveTo,
            AmountDue = amountDue.Value,
            DiscountAmount = 0m,
            TaxAmount = 0m,
            AmountPaid = 0m,
            Currency = "CNY",
            Status = TenantBillingStatus.Pending,
            DueDate = now.AddDays(7),
            LineItemsJson = JsonSerializer.Serialize(lineItems),
            Notes = subscription.Notes
        };

        // 6. 持久化账单
        await billingRepository.AddAsync(billing, cancellationToken);
        await billingRepository.SaveChangesAsync(cancellationToken);

        // 7. 返回详情 DTO
        return billing.ToBillingDetailDto([], detail.TenantName);
    }
}

