using Baya.Application.Contracts.Persistence;

namespace Baya.Application.Features.Messaging;

/// <summary>
/// Mints the human-facing, UNIQUE, stable ticket <c>reference_code</c> (e.g. <c>TKT-9F3K2A7Q</c>). Collision is
/// astronomically unlikely, but the code is quoted to users and backed by a UNIQUE index, so we collision-check
/// against the store and retry — the index is the authoritative backstop, this is the friendly pre-check.
/// </summary>
public static class TicketReferenceCode
{
    private const string Prefix = "TKT-";
    private const string Alphabet = "ABCDEFGHJKLMNPQRSTUVWXYZ23456789"; // no ambiguous 0/O/1/I
    private const int Length = 8;

    public static async Task<string> MintAsync(ITicketRepository tickets, CancellationToken cancellationToken)
    {
        for (var attempt = 0; attempt < 5; attempt++)
        {
            var code = Generate();
            if (!await tickets.ReferenceCodeExistsAsync(code, cancellationToken))
                return code;
        }

        // Extremely improbable; fall back to a longer, still-checked code rather than loop forever.
        return Prefix + Guid.NewGuid().ToString("N")[..12].ToUpperInvariant();
    }

    private static string Generate()
    {
        var bytes = Guid.NewGuid().ToByteArray();
        var chars = new char[Length];
        for (var i = 0; i < Length; i++)
            chars[i] = Alphabet[bytes[i] % Alphabet.Length];
        return Prefix + new string(chars);
    }
}
