using System.Text;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace Tiku.Infrastructure.Persistence;

internal static class ModelBuilderExtensions
{
    public static void UseSnakeCaseIdentifiers(this ModelBuilder modelBuilder)
    {
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            foreach (var property in entityType.GetProperties()) property.SetColumnName(ToSnakeCase(property.Name));

            foreach (var key in entityType.GetKeys())
                if (key.GetName() is { } keyName)
                    key.SetName(ToSnakeCase(keyName));

            foreach (var foreignKey in entityType.GetForeignKeys())
                if (foreignKey.GetConstraintName() is { } constraintName)
                    foreignKey.SetConstraintName(ToSnakeCase(constraintName));

            foreach (var index in entityType.GetIndexes())
                if (index.GetDatabaseName() is { } indexName)
                    index.SetDatabaseName(ToSnakeCase(indexName));
        }
    }

    public static string ToSnakeCase(string value)
    {
        if (string.IsNullOrWhiteSpace(value)) return value;

        var builder = new StringBuilder(value.Length + 8);
        for (var index = 0; index < value.Length; index++)
        {
            var character = value[index];
            if (char.IsUpper(character) && index > 0 &&
                (char.IsLower(value[index - 1]) ||
                 (index + 1 < value.Length && char.IsLower(value[index + 1]))))
                builder.Append('_');

            builder.Append(char.ToLowerInvariant(character));
        }

        return builder.ToString();
    }
}

internal sealed class SnakeCaseEnumConverter<TEnum>() : ValueConverter<TEnum, string>(
    value => ModelBuilderExtensions.ToSnakeCase(value.ToString()),
    value => Enum.Parse<TEnum>(value.Replace("_", string.Empty), true))
    where TEnum : struct, Enum;