using CMSMicroservice.Application.Common.Interfaces;
using Microsoft.EntityFrameworkCore;

namespace CMSMicroservice.Application.Common;

public static class BlogSlugHelper
{
    private const int MaxSlugLength = 200;

    public static string? NormalizeOptional(string? slug)
    {
        if (string.IsNullOrWhiteSpace(slug))
            return null;

        return slug.Trim().ToLowerInvariant();
    }

    /// <summary>
    /// Builds a URL slug from title (ASCII letters/digits). Persian-only titles yield empty string.
    /// </summary>
    public static string GenerateFromTitle(string title)
    {
        if (string.IsNullOrWhiteSpace(title))
            return string.Empty;

        var sb = new System.Text.StringBuilder();
        var lastWasHyphen = false;

        foreach (var c in title.Trim().ToLowerInvariant())
        {
            if (c is >= 'a' and <= 'z' or >= '0' and <= '9')
            {
                sb.Append(c);
                lastWasHyphen = false;
            }
            else if (c is ' ' or '_' or '-')
            {
                if (sb.Length > 0 && !lastWasHyphen)
                {
                    sb.Append('-');
                    lastWasHyphen = true;
                }
            }
        }

        var result = sb.ToString().Trim('-');
        return result.Length > MaxSlugLength ? result[..MaxSlugLength].TrimEnd('-') : result;
    }

    public static string CreateFallbackSlug() =>
        $"post-{Guid.NewGuid():N}"[..Math.Min(20, MaxSlugLength)];

    public static string ResolveForCreate(string? requestedSlug, string title)
    {
        var normalized = NormalizeOptional(requestedSlug);
        if (!string.IsNullOrEmpty(normalized))
            return normalized;

        var fromTitle = GenerateFromTitle(title);
        return !string.IsNullOrEmpty(fromTitle) ? fromTitle : CreateFallbackSlug();
    }

    public static async Task<string> EnsureUniquePostSlugAsync(
        IApplicationDbContext context,
        string slug,
        long? excludePostId = null,
        CancellationToken cancellationToken = default)
    {
        var candidate = slug;
        var suffix = 2;

        while (await context.BlogPosts.AnyAsync(
            p => p.Slug == candidate && !p.IsDeleted && (excludePostId == null || p.Id != excludePostId.Value),
            cancellationToken))
        {
            var suffixStr = $"-{suffix}";
            var maxBase = MaxSlugLength - suffixStr.Length;
            var basePart = slug.Length > maxBase ? slug[..maxBase].TrimEnd('-') : slug;
            candidate = basePart + suffixStr;
            suffix++;
        }

        return candidate;
    }
}
