using MealPlan.Api.Models;
using Microsoft.EntityFrameworkCore;

namespace MealPlan.Api.Data;

/// <summary>
/// Database-first context for the existing PostgreSQL database.
/// Tables are mapped explicitly; this context never creates or alters schema.
/// </summary>
public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    public DbSet<Recipe> Recipes => Set<Recipe>();
    public DbSet<Ingredient> Ingredients => Set<Ingredient>();
    public DbSet<RecipeStep> RecipeSteps => Set<RecipeStep>();
    public DbSet<ApplicationUser> Users => Set<ApplicationUser>();
    public DbSet<UserDailyGoal> UserDailyGoals => Set<UserDailyGoal>();
    public DbSet<DrinkCatalogItem> DrinkCatalog => Set<DrinkCatalogItem>();
    public DbSet<MealConsumption> MealConsumptions => Set<MealConsumption>();
    public DbSet<DrinkConsumption> DrinkConsumptions => Set<DrinkConsumption>();
    public DbSet<DietReminder> DietReminders => Set<DietReminder>();
    public DbSet<IngredientCategory> IngredientCategories => Set<IngredientCategory>();
    public DbSet<IngredientNutritionCatalogItem> IngredientNutritionCatalog => Set<IngredientNutritionCatalogItem>();
    public DbSet<RefreshTokenEntity> RefreshTokens => Set<RefreshTokenEntity>();
    public DbSet<MealPlanEntry> MealPlanEntries => Set<MealPlanEntry>();
    public DbSet<UserFavoriteRecipe> UserFavoriteRecipes => Set<UserFavoriteRecipe>();
    public DbSet<UserFavoriteCatalogItem> UserFavoriteCatalogItems => Set<UserFavoriteCatalogItem>();
    public DbSet<DietUserProfile> DietUserProfiles => Set<DietUserProfile>();
    public DbSet<DietGeneratorSession> DietGeneratorSessions => Set<DietGeneratorSession>();
    public DbSet<DietGeneratorDraftMeal> DietGeneratorDraftMeals => Set<DietGeneratorDraftMeal>();
    public DbSet<DietGeneratorDraftMealIngredient> DietGeneratorDraftMealIngredients =>
        Set<DietGeneratorDraftMealIngredient>();
    public DbSet<RecipeGeneratorSession> RecipeGeneratorSessions => Set<RecipeGeneratorSession>();

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);
        
        modelBuilder.HasDefaultSchema("diet");

        modelBuilder.Entity<Recipe>(e =>
        {
            e.HasKey(r => r.Id);
            e.Property(r => r.Id).UseIdentityByDefaultColumn();
            e.Property(r => r.Protein).HasColumnType("numeric(6,2)");
            e.Property(r => r.Fat).HasColumnType("numeric(6,2)");
            e.Property(r => r.Carbs).HasColumnType("numeric(6,2)");

            e.HasMany(r => r.Ingredients)
                .WithOne(i => i.Recipe!)
                .HasForeignKey(i => i.RecipeId)
                .OnDelete(DeleteBehavior.Cascade);

            e.HasMany(r => r.Steps)
                .WithOne(s => s.Recipe!)
                .HasForeignKey(s => s.RecipeId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<Ingredient>(e =>
        {
            e.HasKey(i => i.Id);
            e.Property(i => i.Id).UseIdentityByDefaultColumn();
            e.Property(i => i.AmountGrams).HasColumnType("numeric(8,2)");
            e.HasOne(i => i.CatalogItem)
                .WithMany()
                .HasForeignKey(i => i.CatalogItemId)
                .OnDelete(DeleteBehavior.SetNull);
        });

        modelBuilder.Entity<RecipeStep>(e =>
        {
            e.HasKey(s => s.Id);
            e.Property(s => s.Id).UseIdentityByDefaultColumn();
        });

        modelBuilder.Entity<ApplicationUser>(e =>
        {
            e.HasKey(u => u.Id);
            e.Property(u => u.Id).HasColumnType("uuid");
        });

        modelBuilder.Entity<UserDailyGoal>(e =>
        {
            e.HasKey(g => g.UserId);
            e.Property(g => g.UserId).HasColumnType("uuid");
            e.Property(g => g.ProteinGoalG).HasColumnType("numeric(6,2)");
            e.Property(g => g.FatGoalG).HasColumnType("numeric(6,2)");
            e.Property(g => g.CarbsGoalG).HasColumnType("numeric(6,2)");
            e.HasOne(g => g.User)
                .WithMany()
                .HasForeignKey(g => g.UserId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<DrinkCatalogItem>(e =>
        {
            e.HasKey(d => d.Id);
            e.Property(d => d.Id).UseIdentityByDefaultColumn();
            e.Property(d => d.CaloriesPer100Ml).HasColumnType("numeric(6,2)");
        });

        modelBuilder.Entity<MealConsumption>(e =>
        {
            e.HasKey(m => m.Id);
            e.Property(m => m.Id).UseIdentityByDefaultColumn();
            e.Property(m => m.UserId).HasColumnType("uuid");
            e.Property(m => m.Portions).HasColumnType("numeric(4,2)");
            e.Property(m => m.ProteinG).HasColumnType("numeric(6,2)");
            e.Property(m => m.FatG).HasColumnType("numeric(6,2)");
            e.Property(m => m.CarbsG).HasColumnType("numeric(6,2)");
            e.HasOne(m => m.User)
                .WithMany()
                .HasForeignKey(m => m.UserId)
                .OnDelete(DeleteBehavior.Cascade);
            e.HasOne(m => m.Recipe)
                .WithMany()
                .HasForeignKey(m => m.RecipeId)
                .OnDelete(DeleteBehavior.SetNull);
        });

        modelBuilder.Entity<DrinkConsumption>(e =>
        {
            e.HasKey(d => d.Id);
            e.Property(d => d.Id).UseIdentityByDefaultColumn();
            e.Property(d => d.UserId).HasColumnType("uuid");
            e.HasOne(d => d.User)
                .WithMany()
                .HasForeignKey(d => d.UserId)
                .OnDelete(DeleteBehavior.Cascade);
            e.HasOne(d => d.DrinkCatalog)
                .WithMany()
                .HasForeignKey(d => d.DrinkCatalogId)
                .OnDelete(DeleteBehavior.SetNull);
        });

        modelBuilder.Entity<DietReminder>(e =>
        {
            e.HasKey(r => r.Id);
            e.Property(r => r.Id).UseIdentityByDefaultColumn();
            e.Property(r => r.UserId).HasColumnType("uuid");
            e.HasOne(r => r.User)
                .WithMany()
                .HasForeignKey(r => r.UserId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<IngredientCategory>(e =>
        {
            e.HasKey(c => c.Id);
            e.Property(c => c.Id).UseIdentityByDefaultColumn();
        });

        modelBuilder.Entity<IngredientNutritionCatalogItem>(e =>
        {
            e.HasKey(i => i.Id);
            e.Property(i => i.Id).UseIdentityByDefaultColumn();
            e.Property(i => i.ProteinGPer100G).HasColumnType("numeric(6,2)");
            e.Property(i => i.FatGPer100G).HasColumnType("numeric(6,2)");
            e.Property(i => i.CarbsGPer100G).HasColumnType("numeric(6,2)");
            e.Property(i => i.FiberGPer100G).HasColumnType("numeric(6,2)");
            e.HasOne(i => i.Category)
                .WithMany(c => c.Items)
                .HasForeignKey(i => i.CategoryId)
                .OnDelete(DeleteBehavior.Restrict);
        });

        modelBuilder.Entity<RefreshTokenEntity>(e =>
        {
            e.HasKey(t => t.Token);
            e.Property(t => t.UserId).HasColumnType("uuid");
            e.HasOne(t => t.User)
                .WithMany()
                .HasForeignKey(t => t.UserId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<MealPlanEntry>(e =>
        {
            e.HasKey(m => m.Id);
            e.Property(m => m.Id).UseIdentityByDefaultColumn();
            e.Property(m => m.UserId).HasColumnType("uuid");
            e.Property(m => m.Portions).HasColumnType("numeric(4,2)");
            e.HasOne(m => m.User).WithMany().HasForeignKey(m => m.UserId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(m => m.Recipe).WithMany().HasForeignKey(m => m.RecipeId).OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<UserFavoriteRecipe>(e =>
        {
            e.HasKey(f => new { f.UserId, f.RecipeId });
            e.Property(f => f.UserId).HasColumnType("uuid");
            e.HasOne(f => f.Recipe).WithMany().HasForeignKey(f => f.RecipeId).OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<UserFavoriteCatalogItem>(e =>
        {
            e.HasKey(f => new { f.UserId, f.CatalogItemId });
            e.Property(f => f.UserId).HasColumnType("uuid");
            e.HasOne(f => f.CatalogItem).WithMany().HasForeignKey(f => f.CatalogItemId).OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<DietUserProfile>(e =>
        {
            e.HasKey(p => p.UserId);
            e.Property(p => p.UserId).HasColumnType("uuid");
            e.Property(p => p.HeightCm).HasColumnType("numeric(5,2)");
            e.Property(p => p.WeightKg).HasColumnType("numeric(5,2)");
            e.HasOne(p => p.User)
                .WithMany()
                .HasForeignKey(p => p.UserId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<DietGeneratorSession>(e =>
        {
            e.HasKey(s => s.Id);
            e.Property(s => s.Id).UseIdentityByDefaultColumn();
            e.Property(s => s.UserId).HasColumnType("uuid");
            e.Property(s => s.ProposedProteinG).HasColumnType("numeric(6,2)");
            e.Property(s => s.ProposedFatG).HasColumnType("numeric(6,2)");
            e.Property(s => s.ProposedCarbsG).HasColumnType("numeric(6,2)");
            e.Property(s => s.PreferencesJson).HasColumnType("jsonb");
            e.HasMany(s => s.DraftMeals).WithOne(m => m.Session!).HasForeignKey(m => m.SessionId).OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<DietGeneratorDraftMeal>(e =>
        {
            e.HasKey(m => m.Id);
            e.Property(m => m.Id).UseIdentityByDefaultColumn();
            e.Property(m => m.Portions).HasColumnType("numeric(4,2)");
            e.Property(m => m.ProteinG).HasColumnType("numeric(6,2)");
            e.Property(m => m.FatG).HasColumnType("numeric(6,2)");
            e.Property(m => m.CarbsG).HasColumnType("numeric(6,2)");
            e.HasOne(m => m.Recipe).WithMany().HasForeignKey(m => m.RecipeId).OnDelete(DeleteBehavior.Cascade);
            e.HasMany(m => m.PlannedIngredients).WithOne(i => i.DraftMeal!).HasForeignKey(i => i.DraftMealId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        modelBuilder.Entity<DietGeneratorDraftMealIngredient>(e =>
        {
            e.HasKey(i => i.Id);
            e.Property(i => i.Id).UseIdentityByDefaultColumn();
            e.Property(i => i.AmountGrams).HasColumnType("numeric(8,2)");
            e.HasOne(i => i.SourceIngredient).WithMany().HasForeignKey(i => i.SourceIngredientId)
                .OnDelete(DeleteBehavior.SetNull);
        });

        modelBuilder.Entity<RecipeGeneratorSession>(e =>
        {
            e.HasKey(s => s.Id);
            e.Property(s => s.Id).UseIdentityByDefaultColumn();
            e.Property(s => s.UserId).HasColumnType("uuid");
            e.Property(s => s.ConstraintsJson).HasColumnType("jsonb");
            e.Property(s => s.DraftJson).HasColumnType("jsonb");
            e.HasOne(s => s.SavedRecipe).WithMany().HasForeignKey(s => s.SavedRecipeId).OnDelete(DeleteBehavior.SetNull);
        });
    }
}
