using MediatR;
using TakeoutSaaS.Application.App.Merchants.Dto;
using TakeoutSaaS.Application.App.Merchants.Queries;
using TakeoutSaaS.Application.App.Stores;
using TakeoutSaaS.Application.App.Stores.Dto;
using TakeoutSaaS.Domain.Identity.Repositories;
using TakeoutSaaS.Domain.Merchants.Repositories;
using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Domain.Tenants.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security;
using TakeoutSaaS.Shared.Abstractions.Tenancy;

namespace TakeoutSaaS.Application.App.Merchants.Handlers;

/// <summary>
/// 获取当前商户中心信息查询处理器。
/// </summary>
public sealed class GetCurrentMerchantCenterQueryHandler(
    ICurrentUserAccessor currentUserAccessor,
    ITenantProvider tenantProvider,
    IIdentityUserRepository identityUserRepository,
    IMerchantRepository merchantRepository,
    IStoreRepository storeRepository,
    ITenantRepository tenantRepository)
    : IRequestHandler<GetCurrentMerchantCenterQuery, CurrentMerchantCenterDto>
{
    /// <summary>
    /// 获取当前登录用户可访问的商户中心完整信息。
    /// </summary>
    /// <param name="request">查询请求。</param>
    /// <param name="cancellationToken">取消标记。</param>
    /// <returns>商户中心聚合信息。</returns>
    public async Task<CurrentMerchantCenterDto> Handle(GetCurrentMerchantCenterQuery request, CancellationToken cancellationToken)
    {
        // 1. 校验登录上下文
        var currentUserId = currentUserAccessor.UserId;
        if (currentUserId <= 0)
        {
            throw new BusinessException(ErrorCodes.Unauthorized, "未登录或登录已过期");
        }

        // 2. 校验租户上下文
        var currentTenantId = tenantProvider.GetCurrentTenantId();
        if (currentTenantId <= 0)
        {
            throw new BusinessException(ErrorCodes.BadRequest, "缺少租户标识，请在 Header 指定租户");
        }

        // 3. 校验当前用户归属
        var currentUser = await identityUserRepository.FindByIdAsync(currentUserId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "用户不存在");
        if (currentUser.TenantId != currentTenantId)
        {
            throw new BusinessException(ErrorCodes.Unauthorized, "无权访问当前租户的商户信息");
        }

        // 4. 解析当前用户可访问商户
        var merchantId = ResolveMerchantId(currentUser.MerchantId);

        // 5. 读取商户主体与租户信息
        var merchant = await merchantRepository.FindByIdAsync(merchantId, currentTenantId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "商户不存在");
        var tenant = await tenantRepository.FindByIdAsync(currentTenantId, cancellationToken)
            ?? throw new BusinessException(ErrorCodes.NotFound, "租户不存在");

        // 6. 读取商户关联数据
        var stores = await storeRepository.GetByMerchantIdAsync(merchantId, currentTenantId, cancellationToken);
        var staffs = await merchantRepository.GetStaffAsync(merchantId, currentTenantId, cancellationToken);
        var documents = await merchantRepository.GetDocumentsAsync(merchantId, currentTenantId, cancellationToken);
        var contracts = await merchantRepository.GetContractsAsync(merchantId, currentTenantId, cancellationToken);
        var auditLogs = await merchantRepository.GetAuditLogsAsync(merchantId, currentTenantId, cancellationToken);
        var changeLogs = await merchantRepository.GetChangeLogsAsync(merchantId, currentTenantId, null, cancellationToken);

        // 7. 组装并返回聚合结果
        var storeDtos = MerchantMapping.ToStoreDtos(stores);
        var staffDtos = staffs.Select(StoreMapping.ToDto).ToList();
        return new CurrentMerchantCenterDto
        {
            Merchant = MerchantMapping.ToDetailDto(merchant, tenant.Name, storeDtos),
            Staffs = staffDtos,
            Documents = MerchantMapping.ToDocumentDtos(documents),
            Contracts = MerchantMapping.ToContractDtos(contracts),
            AuditLogs = auditLogs.Select(MerchantMapping.ToDto).ToList(),
            ChangeLogs = changeLogs.Select(MerchantMapping.ToDto).ToList()
        };
    }

    /// <summary>
    /// 解析当前用户绑定的商户标识。
    /// </summary>
    /// <param name="currentUserMerchantId">当前用户绑定的商户 ID。</param>
    /// <returns>商户 ID。</returns>
    private static long ResolveMerchantId(long? currentUserMerchantId)
    {
        // 1. 严格使用用户绑定商户
        if (currentUserMerchantId is > 0)
        {
            return currentUserMerchantId.Value;
        }

        // 2. 未绑定商户直接拒绝访问
        throw new BusinessException(ErrorCodes.Forbidden, "当前用户未绑定商户，禁止访问商户中心");
    }
}
