using Bimix.Domain.Entities;
using Microsoft.EntityFrameworkCore;

namespace Bimix.Infrastructure.Data;

public class BimixDbContext(DbContextOptions<BimixDbContext> options) : DbContext(options)
{
    public DbSet<Product> Products { get; set; }
    public DbSet<SyncState> SyncStates { get; set; }
    public DbSet<User> Users { get; set; }

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        
        // Product properties
        modelBuilder.Entity<Product>().HasKey(x => x.Id);
        modelBuilder.Entity<Product>().Property(x => x.Name).IsRequired().HasMaxLength(512);
        modelBuilder.Entity<Product>().Property(x => x.Code).IsRequired().HasMaxLength(40);
        modelBuilder.Entity<Product>().Property(x => x.Ean).IsRequired().HasMaxLength(50);
        modelBuilder.Entity<Product>().Property(x => x.StockAddresses).IsRequired().HasMaxLength(512);

        // SyncState properties
        modelBuilder.Entity<SyncState>().HasKey((x => x.Entity));
        
        // User properties
        modelBuilder.Entity<User>().HasKey(x => x.Id);
        modelBuilder.Entity<User>().Property(x => x.GoogleId).IsRequired().HasMaxLength(100);
        modelBuilder.Entity<User>().Property(x => x.Email).IsRequired().HasMaxLength(255);
        modelBuilder.Entity<User>().Property(x => x.FullName).IsRequired().HasMaxLength(255);
        modelBuilder.Entity<User>().Property(x => x.IsActive).IsRequired().HasDefaultValue(false);
        modelBuilder.Entity<User>().Property(x => x.LastLoginAt).IsRequired(false);
        
        // User indexes
        modelBuilder.Entity<User>().HasIndex(x => x.GoogleId).IsUnique().HasDatabaseName("IX_Users_GoogleId");
        modelBuilder.Entity<User>().HasIndex(x => x.Email).IsUnique().HasDatabaseName("IX_Users_Email");
        
        // Configure defaults for all CreatedAt and UpdatedAt in entities
        ConfigureBaseEntity(modelBuilder);
    }

    private void ConfigureBaseEntity(ModelBuilder modelBuilder)
    {
        foreach (var entityType in modelBuilder.Model.GetEntityTypes())
        {
            if (typeof(BaseEntity).IsAssignableFrom(entityType.ClrType))
            {
                modelBuilder.Entity(entityType.ClrType)
                    .Property(nameof(BaseEntity.CreatedAt))
                    .HasDefaultValueSql("GETUTCDATE()");
                
                modelBuilder.Entity(entityType.ClrType)
                    .Property(nameof(BaseEntity.UpdatedAt))
                    .HasDefaultValueSql("GETUTCDATE()");
            }
        }
    }
    
    public override int SaveChanges()
    {
        UpdateTimestamps();
        return base.SaveChanges();
    }

    public override Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        UpdateTimestamps();
        return base.SaveChangesAsync(cancellationToken);
    }

    private void UpdateTimestamps()
    {
        var entities = ChangeTracker.Entries<BaseEntity>();
        
        foreach (var entity in entities)
        {
            if (entity.State == EntityState.Added)
            {
                entity.Entity.CreatedAt = DateTime.UtcNow;
                entity.Entity.UpdatedAt = DateTime.UtcNow;
                break;
            }
            else if (entity.State == EntityState.Modified)
            {
                entity.Entity.UpdatedAt = DateTime.UtcNow;
                break;
            }
        }
    }
}