using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;

namespace DodoSSH.Infrastructure;

/// <summary>
/// Maps PostgreSQL's <c>xmin</c> system column as an optimistic concurrency token.
/// </summary>
/// <remarks>
/// <para>
/// Npgsql's <c>UseXminAsConcurrencyToken</c> helper no longer exists in EF 10, so the shadow
/// property is configured directly here rather than repeated in every entity configuration.
/// </para>
/// <para>
/// <c>xmin</c> is a system column that PostgreSQL maintains, so it must never appear in a
/// <c>CREATE TABLE</c>. That is what <see cref="RelationalPropertyBuilderExtensions.HasColumnName"/>
/// combined with <c>ValueGeneratedOnAddOrUpdate</c> achieves; an
/// <c>Infrastructure</c> test asserts the generated DDL does not declare it.
/// </para>
/// <para>
/// This token is strictly internal. It is never exposed to clients: <c>xmin</c> is not stable
/// across <c>VACUUM FREEZE</c>, so using it as a sync cursor would silently break. Client-visible
/// versioning is the separate monotonic <c>Version</c> column on item rows.
/// </para>
/// </remarks>
public static class XminConcurrency
{
    /// <summary>Name of the shadow property and of the PostgreSQL system column.</summary>
    public const string PropertyName = "xmin";

    /// <summary>Configures <c>xmin</c> as this entity's concurrency token.</summary>
    public static EntityTypeBuilder<TEntity> UseXminConcurrencyToken<TEntity>(
        this EntityTypeBuilder<TEntity> builder)
        where TEntity : class
    {
        ArgumentNullException.ThrowIfNull(builder);

        builder.Property<uint>(PropertyName)
            .HasColumnName(PropertyName)
            .HasColumnType("xid")
            .ValueGeneratedOnAddOrUpdate()
            .IsConcurrencyToken();

        return builder;
    }
}
