// <copyright file="SnakeCaseNamingConvention.cs" company="PlaceholderCompany">
// Copyright (c) PlaceholderCompany. All rights reserved.
// </copyright>

namespace Jellyfin.Database.Providers.Postgres;

using System.Text.RegularExpressions;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;

/// <summary>
/// EF Core convention that maps all entity property names to snake_case column names.
/// Applied only by the PostgreSQL provider so SQLite is unaffected.
/// </summary>
public sealed class SnakeCaseNamingConvention : IPropertyAddedConvention
{
    private static readonly Regex AcronymBoundaryRegex =
        new(@"([A-Z]+)([A-Z][a-z])", RegexOptions.Compiled);

    private static readonly Regex LowerToUpperRegex =
        new(@"([a-z\d])([A-Z])", RegexOptions.Compiled);

    /// <inheritdoc />
    public void ProcessPropertyAdded(
        IConventionPropertyBuilder propertyBuilder,
        IConventionContext<IConventionPropertyBuilder> context)
    {
        propertyBuilder.HasColumnName(ToSnakeCase(propertyBuilder.Metadata.Name));
    }

    /// <summary>Converts a PascalCase identifier to snake_case.</summary>
    /// <param name="name">The identifier to convert.</param>
    /// <returns>The snake_case representation of the identifier.</returns>
    internal static string ToSnakeCase(string name)
    {
        name = AcronymBoundaryRegex.Replace(name, "$1_$2");
        name = LowerToUpperRegex.Replace(name, "$1_$2");
        return name.ToLowerInvariant();
    }
}
