using System.Text.Json;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Metadata.Builders;
using Tiku.Domain.Common;
using Tiku.Domain.Tenancy;

namespace Tiku.Infrastructure.Persistence.Configurations;

internal static class ConfigurationSupport
{
    public static void ConfigureEntity<TEntity>(
        this EntityTypeBuilder<TEntity> builder,
        string tableName)
        where TEntity : Entity
    {
        builder.ToTable(tableName);
        builder.HasKey(entity => entity.Id);
        builder.Property(entity => entity.Id).HasDefaultValueSql("gen_random_uuid()");
    }

    public static void ConfigureTenantEntity<TEntity>(
        this EntityTypeBuilder<TEntity> builder,
        string tableName)
        where TEntity : TenantEntity
    {
        builder.ConfigureEntity(tableName);
        builder.HasAlternateKey(entity => new { entity.TenantId, entity.Id });
        builder.HasOne<Tenant>()
            .WithMany()
            .HasForeignKey(entity => entity.TenantId)
            .OnDelete(DeleteBehavior.Cascade);
    }

    public static void ConfigureTimestamps<TEntity>(this EntityTypeBuilder<TEntity> builder)
        where TEntity : class, IHasTimestamps
    {
        builder.Property(entity => entity.CreatedAt).HasDefaultValueSql("now()");
        builder.Property(entity => entity.UpdatedAt).HasDefaultValueSql("now()");
    }

    public static PropertyBuilder<JsonElement> IsJson(
        this PropertyBuilder<JsonElement> property,
        string defaultJson)
    {
        return property
            .HasColumnType("jsonb")
            .HasDefaultValueSql($"'{defaultJson}'::jsonb");
    }

    public static PropertyBuilder<TEnum> HasSnakeCaseEnum<TEnum>(
        this PropertyBuilder<TEnum> property,
        int maxLength = 32)
        where TEnum : struct, Enum
    {
        return property
            .HasConversion(new SnakeCaseEnumConverter<TEnum>())
            .HasMaxLength(maxLength);
    }

    public static PropertyBuilder<TEnum?> HasNullableSnakeCaseEnum<TEnum>(
        this PropertyBuilder<TEnum?> property,
        int maxLength = 32)
        where TEnum : struct, Enum
    {
        return property
            .HasConversion(
                value => value.HasValue
                    ? ModelBuilderExtensions.ToSnakeCase(value.Value.ToString())
                    : null,
                value => string.IsNullOrWhiteSpace(value)
                    ? null
                    : Enum.Parse<TEnum>(value.Replace("_", string.Empty), true))
            .HasMaxLength(maxLength);
    }
}
