using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.Stores.Commands;
using TakeoutSaaS.Application.App.Stores.Queries;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.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.Stores.Handlers;

/// <summary>
/// 提交门店审核处理器。
/// </summary>
public sealed class SubmitStoreAuditCommandHandler(
    IStoreRepository storeRepository,
    ITenantProvider tenantProvider,
    ICurrentUserAccessor currentUserAccessor,
    IMediator mediator,
    ILogger<SubmitStoreAuditCommandHandler> logger)
    : IRequestHandler<SubmitStoreAuditCommand, bool>
{
    /// <inheritdoc />
    public async Task<bool> Handle(SubmitStoreAuditCommand request, CancellationToken cancellationToken)
    {
        // 1. 校验门店存在
        var tenantId = tenantProvider.GetCurrentTenantId();
        var store = await storeRepository.FindByIdAsync(request.StoreId, tenantId, cancellationToken);
        if (store is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
        }

        if (store.AuditStatus is not StoreAuditStatus.Draft and not StoreAuditStatus.Rejected)
        {
            throw new BusinessException(ErrorCodes.Conflict, "门店不处于可提交状态");
        }

        // 2. (空行后) 处理同主体门店直接激活
        var now = DateTime.UtcNow;
        if (store.OwnershipType == StoreOwnershipType.SameEntity)
        {
            var previousStatus = store.AuditStatus;
            store.AuditStatus = StoreAuditStatus.Activated;
            store.BusinessStatus = StoreBusinessStatus.Resting;
            store.SubmittedAt ??= now;
            store.ActivatedAt ??= now;
            store.RejectionReason = null;

            await storeRepository.UpdateStoreAsync(store, cancellationToken);
            await storeRepository.AddAuditRecordAsync(new StoreAuditRecord
            {
                StoreId = store.Id,
                Action = StoreAuditAction.AutoActivate,
                PreviousStatus = previousStatus,
                NewStatus = store.AuditStatus,
                OperatorId = ResolveOperatorId(),
                OperatorName = ResolveOperatorName(),
                Remarks = "同主体门店自动激活"
            }, cancellationToken);
            await storeRepository.SaveChangesAsync(cancellationToken);
            logger.LogInformation("门店 {StoreId} 同主体自动激活", store.Id);

            return true;
        }

        // 3. (空行后) 校验资质完整性
        var checkResult = await mediator.Send(new CheckStoreQualificationsQuery { StoreId = request.StoreId }, cancellationToken);
        if (!checkResult.CanSubmitAudit)
        {
            throw new BusinessException(ErrorCodes.ValidationFailed, "门店资质不完整，无法提交审核");
        }

        // 4. (空行后) 更新审核状态
        var action = store.AuditStatus == StoreAuditStatus.Rejected
            ? StoreAuditAction.Resubmit
            : StoreAuditAction.Submit;
        var previous = store.AuditStatus;
        store.AuditStatus = StoreAuditStatus.Pending;
        store.BusinessStatus = StoreBusinessStatus.Resting;
        store.SubmittedAt = now;
        store.RejectionReason = null;

        await storeRepository.UpdateStoreAsync(store, cancellationToken);
        await storeRepository.AddAuditRecordAsync(new StoreAuditRecord
        {
            StoreId = store.Id,
            Action = action,
            PreviousStatus = previous,
            NewStatus = store.AuditStatus,
            OperatorId = ResolveOperatorId(),
            OperatorName = ResolveOperatorName(),
            Remarks = action == StoreAuditAction.Resubmit ? "门店重新提交审核" : "门店提交审核"
        }, cancellationToken);
        await storeRepository.SaveChangesAsync(cancellationToken);
        logger.LogInformation("门店 {StoreId} 提交审核", store.Id);

        return true;
    }

    private long? ResolveOperatorId()
    {
        var id = currentUserAccessor.UserId;
        return id == 0 ? null : id;
    }

    private string ResolveOperatorName()
    {
        var id = currentUserAccessor.UserId;
        return id == 0 ? "system" : $"user:{id}";
    }
}
