using Microsoft.EntityFrameworkCore;
using Database.Models;

namespace Database
{
    public class DatabaseContext : DbContext
    {
        public DatabaseContext(DbContextOptions<DatabaseContext> options) : base(options)
        {
        }

        // Core Entities
        public DbSet<User> Users { get; set; }
        public DbSet<Package> Packages { get; set; }
        public DbSet<PackageConfiguration> PackageConfigurations { get; set; }
        public DbSet<Project> Projects { get; set; }
        public DbSet<Build> Builds { get; set; }
        public DbSet<BuildCommit> BuildCommits { get; set; }

        // FogBugz Integration
        public DbSet<FogBugzCase> FogBugzCases { get; set; }
        public DbSet<FogBugzEvent> FogBugzEvents { get; set; }

        // Publishing Workflow
        public DbSet<Publication> Publications { get; set; }
        public DbSet<PublishingStep> PublishingSteps { get; set; }

        // Provider Configurations
        public DbSet<StorageProvider> StorageProviders { get; set; }
        public DbSet<HelpCenterProvider> HelpCenterProviders { get; set; }

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

            // Configure soft delete filter
            modelBuilder.Entity<User>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<Package>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<PackageConfiguration>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<Project>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<Build>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<BuildCommit>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<FogBugzCase>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<FogBugzEvent>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<Publication>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<PublishingStep>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<StorageProvider>().HasQueryFilter(e => !e.IsDeleted);
            modelBuilder.Entity<HelpCenterProvider>().HasQueryFilter(e => !e.IsDeleted);

            // Configure relationships
            ConfigureUserRelationships(modelBuilder);
            ConfigurePackageRelationships(modelBuilder);
            ConfigureProjectRelationships(modelBuilder);
            ConfigureBuildRelationships(modelBuilder);
            ConfigureFogBugzRelationships(modelBuilder);
            ConfigurePublishingRelationships(modelBuilder);
            ConfigureProviderRelationships(modelBuilder);

            // Configure indexes
            ConfigureIndexes(modelBuilder);

            // Configure database constraints
            ConfigureConstraints(modelBuilder);
        }

        private static void ConfigureUserRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<User>()
                .HasIndex(u => u.Username)
                .IsUnique();
        }

        private static void ConfigurePackageRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Package>()
                .HasOne(p => p.Project)
                .WithMany(pr => pr.Packages)
                .HasForeignKey(p => p.ProjectId)
                .OnDelete(DeleteBehavior.Restrict);

            modelBuilder.Entity<Package>()
                .HasOne(p => p.SourceBuild)
                .WithMany()
                .HasForeignKey(p => p.SourceBuildId)
                .OnDelete(DeleteBehavior.Restrict);

            modelBuilder.Entity<PackageConfiguration>()
                .HasOne(pc => pc.Package)
                .WithOne(p => p.Configuration)
                .HasForeignKey<PackageConfiguration>(pc => pc.PackageId)
                .OnDelete(DeleteBehavior.Cascade);
        }

        private static void ConfigureProjectRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Project>()
                .HasIndex(p => p.CCNetProjectName)
                .IsUnique();
        }

        private static void ConfigureBuildRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Build>()
                .HasOne(b => b.Project)
                .WithMany(p => p.Builds)
                .HasForeignKey(b => b.ProjectId)
                .OnDelete(DeleteBehavior.Cascade);

            modelBuilder.Entity<Build>()
                .HasIndex(b => new { b.ProjectId, b.BuildNumber })
                .IsUnique();

            modelBuilder.Entity<BuildCommit>()
                .HasOne(bc => bc.Build)
                .WithMany(b => b.Commits)
                .HasForeignKey(bc => bc.BuildId)
                .OnDelete(DeleteBehavior.Cascade);

            modelBuilder.Entity<BuildCommit>()
                .HasOne(bc => bc.FogBugzCase)
                .WithMany()
                .HasForeignKey(bc => bc.FogBugzCaseId)
                .OnDelete(DeleteBehavior.SetNull);
        }

        private static void ConfigureFogBugzRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<FogBugzCase>()
                .HasIndex(c => c.CaseId)
                .IsUnique();

            modelBuilder.Entity<FogBugzEvent>()
                .HasOne(e => e.Case)
                .WithMany(c => c.Events)
                .HasForeignKey(e => e.CaseId)
                .OnDelete(DeleteBehavior.Cascade);
        }

        private static void ConfigurePublishingRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<Publication>()
                .HasOne(pub => pub.Package)
                .WithMany(p => p.Publications)
                .HasForeignKey(pub => pub.PackageId)
                .OnDelete(DeleteBehavior.Cascade);

            modelBuilder.Entity<PublishingStep>()
                .HasOne(ps => ps.Publication)
                .WithMany(p => p.Steps)
                .HasForeignKey(ps => ps.PublicationId)
                .OnDelete(DeleteBehavior.Cascade);
        }

        private static void ConfigureProviderRelationships(ModelBuilder modelBuilder)
        {
            modelBuilder.Entity<StorageProvider>()
                .HasIndex(sp => sp.Name)
                .IsUnique();

            modelBuilder.Entity<HelpCenterProvider>()
                .HasIndex(hcp => hcp.Name)
                .IsUnique();
        }

        private static void ConfigureIndexes(ModelBuilder modelBuilder)
        {
            // Performance indexes
            modelBuilder.Entity<Build>()
                .HasIndex(b => b.Status);

            modelBuilder.Entity<Build>()
                .HasIndex(b => b.StartTime);

            modelBuilder.Entity<BuildCommit>()
                .HasIndex(bc => bc.FogBugzCaseId);

            modelBuilder.Entity<BuildCommit>()
                .HasIndex(bc => bc.CommitDate);

            modelBuilder.Entity<FogBugzCase>()
                .HasIndex(c => c.Status);

            modelBuilder.Entity<FogBugzCase>()
                .HasIndex(c => c.LastUpdated);

            modelBuilder.Entity<FogBugzEvent>()
                .HasIndex(e => e.EventDate);

            modelBuilder.Entity<Publication>()
                .HasIndex(p => p.Status);

            modelBuilder.Entity<Publication>()
                .HasIndex(p => p.PublishedAt);

            modelBuilder.Entity<PublishingStep>()
                .HasIndex(ps => ps.Status);
        }

        private static void ConfigureConstraints(ModelBuilder modelBuilder)
        {
            // String length constraints
            modelBuilder.Entity<User>()
                .Property(u => u.Username)
                .HasMaxLength(100)
                .IsRequired();

            modelBuilder.Entity<User>()
                .Property(u => u.Role)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<Package>()
                .Property(p => p.Title)
                .HasMaxLength(200)
                .IsRequired();

            modelBuilder.Entity<Package>()
                .Property(p => p.Version)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<Package>()
                .Property(p => p.Status)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<Project>()
                .Property(p => p.Name)
                .HasMaxLength(200)
                .IsRequired();

            modelBuilder.Entity<Project>()
                .Property(p => p.CCNetProjectName)
                .HasMaxLength(200)
                .IsRequired();

            modelBuilder.Entity<Build>()
                .Property(b => b.BuildNumber)
                .HasMaxLength(100)
                .IsRequired();

            modelBuilder.Entity<Build>()
                .Property(b => b.Status)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<BuildCommit>()
                .Property(bc => bc.CommitHash)
                .HasMaxLength(40);

            modelBuilder.Entity<BuildCommit>()
                .Property(bc => bc.User)
                .HasMaxLength(100);

            modelBuilder.Entity<FogBugzCase>()
                .Property(c => c.Title)
                .HasMaxLength(500)
                .IsRequired();

            modelBuilder.Entity<FogBugzCase>()
                .Property(c => c.Status)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<FogBugzEvent>()
                .Property(e => e.EventType)
                .HasMaxLength(100)
                .IsRequired();

            modelBuilder.Entity<FogBugzEvent>()
                .Property(e => e.User)
                .HasMaxLength(100);

            modelBuilder.Entity<Publication>()
                .Property(p => p.Status)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<PublishingStep>()
                .Property(ps => ps.StepName)
                .HasMaxLength(200)
                .IsRequired();

            modelBuilder.Entity<PublishingStep>()
                .Property(ps => ps.Status)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<StorageProvider>()
                .Property(sp => sp.Name)
                .HasMaxLength(200)
                .IsRequired();

            modelBuilder.Entity<StorageProvider>()
                .Property(sp => sp.Type)
                .HasMaxLength(50)
                .IsRequired();

            modelBuilder.Entity<HelpCenterProvider>()
                .Property(hcp => hcp.Name)
                .HasMaxLength(200)
                .IsRequired();

            modelBuilder.Entity<HelpCenterProvider>()
                .Property(hcp => hcp.Type)
                .HasMaxLength(50)
                .IsRequired();

            // JSON column configuration
            modelBuilder.Entity<PackageConfiguration>()
                .Property(pc => pc.StorageSettings)
                .HasColumnType("jsonb");

            modelBuilder.Entity<PackageConfiguration>()
                .Property(pc => pc.HelpCenterSettings)
                .HasColumnType("jsonb");

            modelBuilder.Entity<BuildCommit>()
                .Property(bc => bc.ModifiedFiles)
                .HasColumnType("jsonb");

            modelBuilder.Entity<Publication>()
                .Property(p => p.PublicationDetails)
                .HasColumnType("jsonb");

            modelBuilder.Entity<StorageProvider>()
                .Property(sp => sp.Configuration)
                .HasColumnType("jsonb");

            modelBuilder.Entity<HelpCenterProvider>()
                .Property(hcp => hcp.Configuration)
                .HasColumnType("jsonb");

            // Check constraints
            modelBuilder.Entity<PublishingStep>()
                .HasCheckConstraint("CK_PublishingStep_ProgressPercent", 
                    "\"ProgressPercent\" >= 0 AND \"ProgressPercent\" <= 100");

            modelBuilder.Entity<User>()
                .HasCheckConstraint("CK_User_Role", 
                    "\"Role\" IN ('Admin', 'User', 'ReadOnly')");

            modelBuilder.Entity<Package>()
                .HasCheckConstraint("CK_Package_Status", 
                    "\"Status\" IN ('Draft', 'Ready', 'Publishing', 'Published', 'Failed')");

            modelBuilder.Entity<Build>()
                .HasCheckConstraint("CK_Build_Status", 
                    "\"Status\" IN ('Success', 'Failure', 'Exception', 'Cancelled', 'Unknown')");

            modelBuilder.Entity<Publication>()
                .HasCheckConstraint("CK_Publication_Status", 
                    "\"Status\" IN ('Pending', 'InProgress', 'Completed', 'Failed', 'Cancelled')");

            modelBuilder.Entity<PublishingStep>()
                .HasCheckConstraint("CK_PublishingStep_Status", 
                    "\"Status\" IN ('Pending', 'InProgress', 'Completed', 'Failed', 'Skipped')");
        }
    }
}