using Dapper;
using Npgsql;

namespace Books.Api.EventFlow.Repositories;

/// <summary>
/// Service for generating sequential order numbers per company per year.
/// Uses a database sequence pattern for thread-safe number generation.
/// </summary>
public class OrderNumberService(NpgsqlDataSource dataSource) : IOrderNumberService
{
    public async Task<string> GetNextOrderNumberAsync(
        string companyId,
        DateOnly orderDate,
        CancellationToken cancellationToken = default)
    {
        await using var connection = await dataSource.OpenConnectionAsync(cancellationToken);

        var year = orderDate.Year;
        var prefix = $"ORD-{year}-";

        // Use advisory lock to prevent race conditions
        var lockKey = HashCode.Combine(companyId, "order", year);

        await connection.ExecuteAsync(
            "SELECT pg_advisory_lock(@LockKey)",
            new { LockKey = lockKey });

        try
        {
            // Get current max number for this company/year
            var sql = """
                SELECT COALESCE(MAX(
                    CAST(SUBSTRING(order_number FROM '\d+$') AS INTEGER)
                ), 0)
                FROM order_read_models
                WHERE company_id = @CompanyId
                AND order_number LIKE @Prefix || '%'
                """;

            var currentMax = await connection.QuerySingleAsync<int>(
                sql, new { CompanyId = companyId, Prefix = prefix });

            var nextNumber = currentMax + 1;
            return $"{prefix}{nextNumber:D4}";
        }
        finally
        {
            await connection.ExecuteAsync(
                "SELECT pg_advisory_unlock(@LockKey)",
                new { LockKey = lockKey });
        }
    }
}
