using System.Data;
using System.Data.Common;
using MediatR;
using Microsoft.Extensions.Logging;
using TakeoutSaaS.Application.App.StoreAudits.Commands;
using TakeoutSaaS.Application.App.StoreAudits.Dto;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Stores.Enums;
using TakeoutSaaS.Domain.Stores.Repositories;
using TakeoutSaaS.Shared.Abstractions.Constants;
using TakeoutSaaS.Shared.Abstractions.Data;
using TakeoutSaaS.Shared.Abstractions.Exceptions;
using TakeoutSaaS.Shared.Abstractions.Security;

namespace TakeoutSaaS.Application.App.StoreAudits.Handlers;

/// <summary>
/// 审核通过处理器。
/// </summary>
public sealed class ApproveStoreCommandHandler(
    IStoreRepository storeRepository,
    IDapperExecutor dapperExecutor,
    ICurrentUserAccessor currentUserAccessor,
    ILogger<ApproveStoreCommandHandler> logger)
    : IRequestHandler<ApproveStoreCommand, StoreAuditActionResultDto>
{
    /// <inheritdoc />
    public async Task<StoreAuditActionResultDto> Handle(ApproveStoreCommand request, CancellationToken cancellationToken)
    {
        // 1. 获取门店快照
        var snapshot = await QueryStoreSnapshotAsync(request.StoreId, cancellationToken);
        if (!snapshot.HasValue)
        {
            throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
        }

        // 1.1 (空行后) 校验审核状态
        if (snapshot.Value.AuditStatus != StoreAuditStatus.Pending)
        {
            throw new BusinessException(ErrorCodes.Conflict, "门店不处于待审核状态");
        }

        // 2. (空行后) 获取门店实体
        var store = await storeRepository.FindByIdAsync(request.StoreId, snapshot.Value.TenantId, cancellationToken);
        if (store is null)
        {
            throw new BusinessException(ErrorCodes.NotFound, "门店不存在");
        }

        // 3. (空行后) 更新状态并记录审核
        var previousStatus = store.AuditStatus;
        var now = DateTime.UtcNow;
        store.AuditStatus = StoreAuditStatus.Activated;
        store.BusinessStatus = StoreBusinessStatus.Resting;
        store.ActivatedAt ??= now;
        store.RejectionReason = null;
        store.ClosureReason = null;
        store.ClosureReasonText = null;

        await storeRepository.UpdateStoreAsync(store, cancellationToken);
        await storeRepository.AddAuditRecordAsync(new StoreAuditRecord
        {
            StoreId = store.Id,
            Action = StoreAuditAction.Approve,
            PreviousStatus = previousStatus,
            NewStatus = store.AuditStatus,
            OperatorId = ResolveOperatorId(),
            OperatorName = ResolveOperatorName(),
            Remarks = request.Remark
        }, cancellationToken);
        await storeRepository.SaveChangesAsync(cancellationToken);
        logger.LogInformation("门店 {StoreId} 审核通过", store.Id);

        // 4. (空行后) 返回结果
        return new StoreAuditActionResultDto
        {
            StoreId = store.Id,
            AuditStatus = store.AuditStatus,
            BusinessStatus = store.BusinessStatus,
            Message = "门店已激活"
        };
    }

    private async Task<(long TenantId, StoreAuditStatus AuditStatus, StoreBusinessStatus BusinessStatus)?> QueryStoreSnapshotAsync(
        long storeId,
        CancellationToken cancellationToken)
    {
        // 1. 查询门店基础字段
        return await dapperExecutor.QueryAsync<(long TenantId, StoreAuditStatus AuditStatus, StoreBusinessStatus BusinessStatus)?>(
            DatabaseConstants.AppDataSource,
            DatabaseConnectionRole.Read,
            async (connection, token) =>
            {
                await using var command = CreateCommand(
                    connection,
                    BuildStoreSnapshotSql(),
                    [
                        ("storeId", storeId)
                    ]);

                // 1.1 (空行后) 执行查询
                await using var reader = await command.ExecuteReaderAsync(token);
                if (!await reader.ReadAsync(token))
                {
                    return null;
                }

                // 1.2 (空行后) 返回快照
                return (
                    reader.GetInt64(reader.GetOrdinal("TenantId")),
                    (StoreAuditStatus)reader.GetInt32(reader.GetOrdinal("AuditStatus")),
                    (StoreBusinessStatus)reader.GetInt32(reader.GetOrdinal("BusinessStatus")));
            },
            cancellationToken);
    }

    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}";
    }

    private static string BuildStoreSnapshotSql()
    {
        return """
            select
              s."TenantId",
              s."AuditStatus",
              s."BusinessStatus"
            from public.stores s
            where s."DeletedAt" is null
              and s."Id" = @storeId;
            """;
    }

    private static DbCommand CreateCommand(IDbConnection connection, string sql, (string Name, object? Value)[] parameters)
    {
        var command = connection.CreateCommand();
        command.CommandText = sql;

        // 1. (空行后) 绑定参数
        foreach (var (name, value) in parameters)
        {
            var p = command.CreateParameter();
            p.ParameterName = name;
            p.Value = value ?? DBNull.Value;
            command.Parameters.Add(p);
        }

        return (DbCommand)command;
    }
}
