using MediatR;
using Microsoft.Extensions.Logging;
using System.Security.Cryptography;
using TakeoutSaaS.Application.App.Common.Geo;
using TakeoutSaaS.Application.App.Merchants.Commands;
using TakeoutSaaS.Application.App.Merchants.Dto;
using TakeoutSaaS.Domain.Merchants.Entities;
using TakeoutSaaS.Domain.Merchants.Repositories;

namespace TakeoutSaaS.Application.App.Merchants.Handlers;

/// <summary>
/// 创建商户命令处理器。
/// </summary>
public sealed class CreateMerchantCommandHandler(
    IMerchantRepository merchantRepository,
    IAddressGeocodingService geocodingService,
    ILogger<CreateMerchantCommandHandler> logger)
    : IRequestHandler<CreateMerchantCommand, MerchantDto>
{
    /// <inheritdoc />
    public async Task<MerchantDto> Handle(CreateMerchantCommand request, CancellationToken cancellationToken)
    {
        // 1. 构建商户实体
        var merchant = new Merchant
        {
            BrandName = request.BrandName.Trim(),
            BrandAlias = request.BrandAlias?.Trim(),
            LogoUrl = request.LogoUrl?.Trim(),
            Category = request.Category?.Trim(),
            ContactPhone = request.ContactPhone.Trim(),
            ContactEmail = request.ContactEmail?.Trim(),
            Province = request.Province?.Trim(),
            City = request.City?.Trim(),
            District = request.District?.Trim(),
            Address = request.Address?.Trim(),
            Status = request.Status,
            RowVersion = RandomNumberGenerator.GetBytes(16),
            JoinedAt = DateTime.UtcNow
        };
        await TryGeocodeMerchantAsync(merchant, cancellationToken);

        // 2. 持久化
        await merchantRepository.AddMerchantAsync(merchant, cancellationToken);
        await merchantRepository.SaveChangesAsync(cancellationToken);

        // 3. 记录日志
        logger.LogInformation("创建商户 {MerchantId} - {BrandName}", merchant.Id, merchant.BrandName);
        return MapToDto(merchant);
    }

    private async Task TryGeocodeMerchantAsync(Merchant merchant, CancellationToken cancellationToken)
    {
        var now = DateTime.UtcNow;
        var candidates = GeoAddressBuilder.BuildMerchantCandidates(merchant);
        if (candidates.Count == 0)
        {
            GeoLocationStateHelper.MarkPending(merchant, "缺少地址信息，等待补全后自动定位", now);
            return;
        }

        string? lastError = null;
        foreach (var candidate in candidates)
        {
            var result = await geocodingService.GeocodeAsync(candidate, cancellationToken);
            if (result.Succeeded && result.Latitude is not null && result.Longitude is not null)
            {
                GeoLocationStateHelper.MarkSuccess(
                    merchant,
                    (double)result.Latitude.Value,
                    (double)result.Longitude.Value,
                    now);
                return;
            }

            lastError = result.Message;
        }

        GeoLocationStateHelper.MarkPending(merchant, lastError ?? "地址地理编码失败，等待自动重试", now);
    }

    private static MerchantDto MapToDto(Merchant merchant) => new()
    {
        Id = merchant.Id,
        TenantId = merchant.TenantId,
        BrandName = merchant.BrandName,
        BrandAlias = merchant.BrandAlias,
        LogoUrl = merchant.LogoUrl,
        Category = merchant.Category,
        ContactPhone = merchant.ContactPhone,
        ContactEmail = merchant.ContactEmail,
        Status = merchant.Status,
        JoinedAt = merchant.JoinedAt,
        CreatedAt = merchant.CreatedAt
    };
}
