using TakeoutSaaS.Domain.Merchants.Entities;
using TakeoutSaaS.Domain.Stores.Entities;
using TakeoutSaaS.Domain.Tenants.Entities;

namespace TakeoutSaaS.Application.App.Common.Geo;

/// <summary>
/// 地理定位地址构建器。
/// </summary>
public static class GeoAddressBuilder
{
    /// <summary>
    /// 构建门店地理编码候选地址。
    /// </summary>
    public static IReadOnlyList<string> BuildStoreCandidates(Store store, Merchant? merchant = null)
    {
        var candidates = new List<string>();
        AddCandidate(candidates, BuildAddress(store.Province, store.City, store.District, store.Address));
        AddCandidate(candidates, store.Address);

        if (merchant is not null)
        {
            AddCandidate(candidates, BuildAddress(merchant.Province, merchant.City, merchant.District, merchant.Address));
            AddCandidate(candidates, BuildAddress(merchant.Province, merchant.City, merchant.District));
            AddCandidate(candidates, BuildAddress(merchant.City, merchant.District));
            AddCandidate(candidates, merchant.Address);
        }

        return candidates;
    }

    /// <summary>
    /// 构建商户地理编码候选地址。
    /// </summary>
    public static IReadOnlyList<string> BuildMerchantCandidates(Merchant merchant)
    {
        var candidates = new List<string>();
        AddCandidate(candidates, BuildAddress(merchant.Province, merchant.City, merchant.District, merchant.Address));
        AddCandidate(candidates, merchant.Address);
        AddCandidate(candidates, BuildAddress(merchant.Province, merchant.City, merchant.District));
        AddCandidate(candidates, BuildAddress(merchant.City, merchant.District));
        return candidates;
    }

    /// <summary>
    /// 构建租户地理编码候选地址。
    /// </summary>
    public static IReadOnlyList<string> BuildTenantCandidates(Tenant tenant)
    {
        var candidates = new List<string>();
        AddCandidate(candidates, BuildAddress(tenant.Country, tenant.Province, tenant.City, tenant.Address));
        AddCandidate(candidates, tenant.Address);
        AddCandidate(candidates, BuildAddress(tenant.Country, tenant.Province, tenant.City));
        AddCandidate(candidates, BuildAddress(tenant.Province, tenant.City));
        return candidates;
    }

    private static string BuildAddress(params string?[] parts)
    {
        var normalized = parts
            .Select(part => part?.Trim())
            .Where(part => !string.IsNullOrWhiteSpace(part))
            .ToArray();

        return normalized.Length == 0 ? string.Empty : string.Join(string.Empty, normalized);
    }

    private static void AddCandidate(ICollection<string> candidates, string? candidate)
    {
        if (string.IsNullOrWhiteSpace(candidate))
        {
            return;
        }

        if (candidates.Any(existing => string.Equals(existing, candidate, StringComparison.OrdinalIgnoreCase)))
        {
            return;
        }

        candidates.Add(candidate);
    }
}
