using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Tenants.Commands;
using TakeoutSaaS.Domain.Identity.Repositories;
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;
using TakeoutSaaS.Shared.Abstractions.Security;

namespace TakeoutSaaS.Application.App.Tenants.Handlers;

/// <summary>
/// 审核租户命令处理器（统一处理通过/驳回）。
/// </summary>
public sealed class ReviewTenantCommandHandler(
    ITenantRepository tenantRepository,
    IIdentityUserRepository identityUserRepository,
    ICurrentUserAccessor currentUserAccessor,
    IIdGenerator idGenerator,
    ILogger<ReviewTenantCommandHandler> logger)
    : IRequestHandler<ReviewTenantCommand>
{
    /// <inheritdoc />
    public async Task Handle(ReviewTenantCommand request, CancellationToken cancellationToken)
    {
        // 1. 解析租户 ID
        if (!long.TryParse(request.TenantId, out var tenantId) || tenantId <= 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "租户 ID 无效");
        }

        // 2. 获取租户（带跟踪）
        var tenant = await tenantRepository.GetByIdForUpdateAsync(tenantId, cancellationToken);
        if (tenant is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
        }

        // 3. 校验租户状态（只有待审核状态才能审核）
        if (tenant.Status != TenantStatus.PendingReview)
        {
            throw new BusinessException(ErrorCodes.BadRequest, $"租户当前状态为 {tenant.Status}，无法审核");
        }

        // 4. 校验是否已领取审核
        var existingClaim = await tenantRepository.GetActiveReviewClaimAsync(tenantId, cancellationToken);
        if (existingClaim is null)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "请先领取审核");
        }

        if (existingClaim.ClaimedBy != currentUserAccessor.UserId)
        {
            throw new BusinessException(ErrorCodes.Forbidden, $"该审核已被 {existingClaim.ClaimedByName} 领取，无法操作");
        }

        // 5. 获取认证资料（带跟踪）
        var verification = await tenantRepository.GetVerificationForUpdateAsync(tenantId, cancellationToken);
        if (verification is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "租户认证资料不存在");
        }

        // 6. 查询当前用户的显示名称
        var actorName = "system";
        if (currentUserAccessor.IsAuthenticated && currentUserAccessor.UserId != 0)
        {
            var user = await identityUserRepository.FindByIdAsync(currentUserAccessor.UserId, cancellationToken);
            actorName = user?.DisplayName ?? $"用户{currentUserAccessor.UserId}";
        }

        // 7. 根据审核结果处理
        if (request.Approve)
        {
            await HandleApprove(tenant, verification, existingClaim, actorName, request, cancellationToken);
        }
        else
        {
            await HandleReject(tenant, verification, existingClaim, actorName, request, cancellationToken);
        }

        // 8. 保存变更
        await tenantRepository.SaveChangesAsync(cancellationToken);

        logger.LogInformation(
            "租户 {TenantId} 审核{Result}，审核人：{ReviewedBy}",
            tenantId,
            request.Approve ? "通过" : "驳回",
            currentUserAccessor.UserId);
    }

    private async Task HandleApprove(
        Domain.Tenants.Entities.Tenant tenant,
        TenantVerificationProfile verification,
        TenantReviewClaim claim,
        string actorName,
        ReviewTenantCommand request,
        CancellationToken cancellationToken)
    {
        // 1. 更新租户状态
        tenant.Status = TenantStatus.Active;

        // 2. 更新经营模式
        if (request.OperatingMode.HasValue)
        {
            tenant.OperatingMode = request.OperatingMode.Value;
        }

        // 3. 更新认证资料状态
        verification.Status = TenantVerificationStatus.Approved;
        verification.ReviewedAt = DateTime.UtcNow;
        verification.ReviewedBy = currentUserAccessor.UserId;
        verification.ReviewedByName = actorName;

        // 4. 释放领取
        claim.ReleasedAt = DateTime.UtcNow;

        // 5. 添加审核日志
        await tenantRepository.AddAuditLogAsync(new TenantAuditLog
        {
            Id = idGenerator.NextId(),
            TenantId = tenant.Id,
            Action = TenantAuditAction.Approved,
            Title = "审核通过",
            Description = $"审核人：{actorName}",
            OperatorId = currentUserAccessor.UserId,
            OperatorName = actorName,
            PreviousStatus = TenantStatus.PendingReview,
            CurrentStatus = TenantStatus.Active
        }, cancellationToken);
    }

    private async Task HandleReject(
        Domain.Tenants.Entities.Tenant tenant,
        TenantVerificationProfile verification,
        TenantReviewClaim claim,
        string actorName,
        ReviewTenantCommand request,
        CancellationToken cancellationToken)
    {
        // 1. 校验驳回原因
        var rejectReason = request.Reason?.Trim();
        if (string.IsNullOrWhiteSpace(rejectReason))
        {
            throw new BusinessException(ErrorCodes.BadRequest, "驳回原因不能为空");
        }

        // 2. 更新认证资料状态（租户状态保持 PendingReview，等待重新提交）
        verification.Status = TenantVerificationStatus.Rejected;
        verification.ReviewedAt = DateTime.UtcNow;
        verification.ReviewedBy = currentUserAccessor.UserId;
        verification.ReviewedByName = actorName;
        verification.ReviewRemarks = rejectReason;

        // 3. 释放领取
        claim.ReleasedAt = DateTime.UtcNow;

        // 4. 添加审核日志
        await tenantRepository.AddAuditLogAsync(new TenantAuditLog
        {
            Id = idGenerator.NextId(),
            TenantId = tenant.Id,
            Action = TenantAuditAction.Rejected,
            Title = "审核驳回",
            Description = $"审核人：{actorName}，驳回原因：{rejectReason}",
            OperatorId = currentUserAccessor.UserId,
            OperatorName = actorName,
            CurrentStatus = tenant.Status
        }, cancellationToken);
    }
}
