using MediatR;
using TakeoutSaaS.Application.App.Personal.Dto;
using TakeoutSaaS.Application.App.Personal.Queries;
using TakeoutSaaS.Application.App.Personal.Services;
using TakeoutSaaS.Domain.Identity.Enums;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;

namespace TakeoutSaaS.Application.App.Personal.Handlers;

/// <summary>
/// 获取个人中心总览处理器。
/// </summary>
public sealed class GetPersonalOverviewQueryHandler(
    PersonalContextService personalContextService,
    PersonalMaskingService personalMaskingService,
    PersonalModuleStatusService moduleStatusService,
    IIdentityUserRepository identityUserRepository,
    ITenantRepository tenantRepository,
    ITenantPackageRepository tenantPackageRepository,
    IMerchantRepository merchantRepository,
    IMediator mediator)
    : IRequestHandler<GetPersonalOverviewQuery, PersonalOverviewDto>
{
    /// <summary>
    /// 处理查询。
    /// </summary>
    /// <param name="request">查询请求。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>总览结果。</returns>
    public async Task<PersonalOverviewDto> Handle(GetPersonalOverviewQuery request, CancellationToken cancellationToken)
    {
        // 1. 获取必需上下文
        var context = personalContextService.GetRequiredContext();
        var traceId = context.TraceId;

        // 2. 初始化总览容器
        var moduleStatuses = new List<PersonalModuleStatusDto>();
        PersonalAccountProfileDto? accountProfile = null;
        PersonalSecuritySnapshotDto? securitySnapshot = null;
        PersonalRolePermissionSummaryDto? roleSummary = null;
        PersonalTenantAffiliationDto? tenantAffiliation = null;

        // 3. 加载账号与安全模块
        var user = await identityUserRepository.FindByIdAsync(context.UserId, cancellationToken)
                   ?? throw new BusinessException(ErrorCodes.NotFound, "用户不存在");
        if (user.TenantId != context.TenantId)
        {
            throw new BusinessException(ErrorCodes.Forbidden, "无权访问其他租户用户数据");
        }

        accountProfile = new PersonalAccountProfileDto
        {
            UserId = user.Id,
            Account = user.Account,
            DisplayName = user.DisplayName,
            AvatarUrl = user.Avatar,
            PhoneMasked = personalMaskingService.MaskPhone(user.Phone),
            EmailMasked = personalMaskingService.MaskEmail(user.Email),
            RegisteredAt = user.CreatedAt
        };
        securitySnapshot = new PersonalSecuritySnapshotDto
        {
            LastLoginAt = user.LastLoginAt,
            FailedLoginCount = user.FailedLoginCount,
            IsLocked = user.Status == IdentityUserStatus.Locked || (user.LockedUntil.HasValue && user.LockedUntil > DateTime.UtcNow),
            LockedUntil = user.LockedUntil,
            IsForceChangePassword = user.MustChangePassword
        };
        moduleStatuses.Add(moduleStatusService.BuildOk("accountSecurity", traceId));

        // 4. 加载角色权限模块（失败可降级）
        try
        {
            roleSummary = await mediator.Send(new GetPersonalRolesQuery(), cancellationToken);
            moduleStatuses.Add(moduleStatusService.BuildOk("roleSummary", traceId));
        }
        catch (Exception ex)
        {
            moduleStatuses.Add(moduleStatusService.BuildIssue("roleSummary", "degraded", ErrorCodes.InternalServerError.ToString(), ex.Message, traceId));
        }

        // 5. 加载租户归属模块（失败可降级）
        try
        {
            var tenant = await tenantRepository.FindByIdAsync(context.TenantId, cancellationToken)
                         ?? throw new BusinessException(ErrorCodes.NotFound, "租户不存在");
            var subscription = await tenantRepository.GetActiveSubscriptionAsync(context.TenantId, cancellationToken);

            string? packageName = null;
            if (subscription is not null)
            {
                var package = await tenantPackageRepository.FindByIdAsync(subscription.TenantPackageId, cancellationToken);
                packageName = package?.Name;
            }

            string? merchantName = null;
            string merchantStatus = "unknown";
            if (user.MerchantId is > 0)
            {
                var merchant = await merchantRepository.FindByIdAsync(user.MerchantId.Value, context.TenantId, cancellationToken);
                merchantName = merchant?.BrandName;
                merchantStatus = merchant?.Status.ToString().ToLowerInvariant() ?? "unknown";
            }

            tenantAffiliation = new PersonalTenantAffiliationDto
            {
                TenantId = tenant.Id,
                TenantName = tenant.Name,
                MerchantId = user.MerchantId,
                MerchantName = merchantName,
                MerchantStatus = merchantStatus,
                PackageName = packageName,
                SubscriptionExpireAt = subscription?.EffectiveTo ?? tenant.EffectiveTo
            };
            moduleStatuses.Add(moduleStatusService.BuildOk("tenantAffiliation", traceId));
        }
        catch (Exception ex)
        {
            moduleStatuses.Add(moduleStatusService.BuildIssue("tenantAffiliation", "degraded", ErrorCodes.InternalServerError.ToString(), ex.Message, traceId));
        }

        // 6. 计算总体状态并返回
        var hasAnyData = accountProfile is not null
                         || securitySnapshot is not null
                         || roleSummary is not null
                         || tenantAffiliation is not null;
        var requestId = string.IsNullOrWhiteSpace(traceId) ? Guid.NewGuid().ToString("N") : traceId;
        var overallStatus = moduleStatusService.ResolveOverallStatus(moduleStatuses, hasAnyData);
        return new PersonalOverviewDto
        {
            RequestId = requestId,
            OverallStatus = overallStatus,
            AccountProfile = accountProfile,
            SecuritySnapshot = securitySnapshot,
            RoleSummary = roleSummary,
            TenantAffiliation = tenantAffiliation,
            QuotaSummary = null,
            ModuleStatuses = moduleStatuses
        };
    }
}
