using System.Reflection;
using CMSMicroservice.Application.Common.Interfaces;
using Microsoft.EntityFrameworkCore.Diagnostics;
using CMSMicroservice.Domain.Entities;
using CMSMicroservice.Domain.Entities.Blog;
using CMSMicroservice.Domain.Entities.Content;
using CMSMicroservice.Domain.Entities.Payment;
using CMSMicroservice.Domain.Entities.Geography;
using CMSMicroservice.Domain.Entities.Order;
using CMSMicroservice.Domain.Entities.DiscountShop;
using CMSMicroservice.Infrastructure.Persistence.Interceptors;
using MediatR;
using Microsoft.EntityFrameworkCore;

namespace CMSMicroservice.Infrastructure.Persistence;

public class ApplicationDbContext :  DbContext, IApplicationDbContext
{
    private readonly IMediator? _mediator;
    private readonly AuditableEntitySaveChangesInterceptor? _auditableEntitySaveChangesInterceptor;
    private readonly HistoryTrackingSaveChangesInterceptor? _historyTrackingInterceptor;

    /// <summary>
    /// Constructor برای design-time (migrations)
    /// </summary>
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) 
        : base(options)
    {
    }

    /// <summary>
    /// Constructor اصلی برای runtime
    /// </summary>
    public ApplicationDbContext(
        DbContextOptions<ApplicationDbContext> options,
        IMediator mediator,
        AuditableEntitySaveChangesInterceptor auditableEntitySaveChangesInterceptor,
        HistoryTrackingSaveChangesInterceptor historyTrackingInterceptor) 
        : base(options)
    {
        _mediator = mediator;
        _auditableEntitySaveChangesInterceptor = auditableEntitySaveChangesInterceptor;
        _historyTrackingInterceptor = historyTrackingInterceptor;
    }
    protected override void OnModelCreating(ModelBuilder builder)
    {
        builder.ApplyConfigurationsFromAssembly(Assembly.GetExecutingAssembly());
        builder.HasDefaultSchema("CMS");
        
        // Ignore MediatR notification types
        builder.Ignore<CMSMicroservice.Domain.Common.BaseEvent>();
        
        base.OnModelCreating(builder);
    }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
    {
        if (_auditableEntitySaveChangesInterceptor != null)
        {
            optionsBuilder.AddInterceptors(_auditableEntitySaveChangesInterceptor);
        }
        
        if (_historyTrackingInterceptor != null)
        {
            optionsBuilder.AddInterceptors(_historyTrackingInterceptor);
        }
        
        // Suppress PendingModelChangesWarning in EF Core 9
        optionsBuilder.ConfigureWarnings(w => w.Ignore(RelationalEventId.PendingModelChangesWarning));
    }

    public override async Task<int> SaveChangesAsync(CancellationToken cancellationToken = default)
    {
        await _mediator.DispatchDomainEvents(this);

        return await base.SaveChangesAsync(cancellationToken);
    }
    public DbSet<UserAddress> UserAddresses => Set<UserAddress>();
    public DbSet<Package> Packages => Set<Package>();
    public DbSet<Role> Roles => Set<Role>();
    public DbSet<Category> Categories => Set<Category>();
    public DbSet<UserRole> UserRoles => Set<UserRole>();
    public DbSet<UserCart> UserCarts => Set<UserCart>();
    public DbSet<ProductGallery> ProductGalleries => Set<ProductGallery>();
    public DbSet<FactorDetails> FactorDetails => Set<FactorDetails>();
    public DbSet<Product> Products => Set<Product>();
    public DbSet<ProductImage> ProductImages => Set<ProductImage>();
    public DbSet<User> Users => Set<User>();
    public DbSet<OtpToken> OtpTokens => Set<OtpToken>();
    public DbSet<Contract> Contracts => Set<Contract>();
    public DbSet<UserContract> UserContracts => Set<UserContract>();
    public DbSet<Tag> Tags => Set<Tag>();
    public DbSet<ProductCategory> ProductCategories => Set<ProductCategory>();
    public DbSet<ProductTag> ProductTags => Set<ProductTag>();
    public DbSet<Transaction> Transactions => Set<Transaction>();
    public DbSet<UserOrder> UserOrders => Set<UserOrder>();
    public DbSet<OrderVAT> OrderVATs => Set<OrderVAT>();
    public DbSet<UserPackagePurchase> UserPackagePurchases => Set<UserPackagePurchase>();
    public DbSet<UserWallet> UserWallets => Set<UserWallet>();
    public DbSet<UserWalletHistory> UserWalletHistories => Set<UserWalletHistory>();
    public DbSet<DayaLoanContract> DayaLoanContracts => Set<DayaLoanContract>();
    
    // Payment
    public DbSet<ManualPayment> ManualPayments => Set<ManualPayment>();
    public DbSet<PaymentTransaction> PaymentTransactions => Set<PaymentTransaction>();
    
    // Message
    public DbSet<PublicMessage> PublicMessages => Set<PublicMessage>();
    
    // ============= Network Club System DbSets =============
    
    // App Version
    public DbSet<AppVersion> AppVersions => Set<AppVersion>();
    
    // Club Management
    public DbSet<ClubMembership> ClubMemberships => Set<ClubMembership>();
    public DbSet<ClubFeature> ClubFeatures => Set<ClubFeature>();
    public DbSet<UserClubFeature> UserClubFeatures => Set<UserClubFeature>();
    public DbSet<ClubMembershipHistory> ClubMembershipHistories => Set<ClubMembershipHistory>();
    public DbSet<ClubMembershipCycle> ClubMembershipCycles => Set<ClubMembershipCycle>();
    public DbSet<ClubMembershipCycleHistory> ClubMembershipCycleHistories => Set<ClubMembershipCycleHistory>();
    public DbSet<PackageHistory> PackageHistories => Set<PackageHistory>();
    public DbSet<PackageFeature> PackageFeatures => Set<PackageFeature>();
    
    // Network
    public DbSet<NetworkWeeklyBalance> NetworkWeeklyBalances => Set<NetworkWeeklyBalance>();
    public DbSet<NetworkMembershipHistory> NetworkMembershipHistories => Set<NetworkMembershipHistory>();
    
    // Week Definitions
    public DbSet<WeekDefinition> WeekDefinitions => Set<WeekDefinition>();
    
    // Commission
    public DbSet<WeeklyCommissionPool> WeeklyCommissionPools => Set<WeeklyCommissionPool>();
    public DbSet<UserCommissionPayout> UserCommissionPayouts => Set<UserCommissionPayout>();
    public DbSet<CommissionPayoutHistory> CommissionPayoutHistories => Set<CommissionPayoutHistory>();
    public DbSet<WorkerExecutionLog> WorkerExecutionLogs => Set<WorkerExecutionLog>();
    
    // ============= Discount Shop DbSets =============
    public DbSet<DiscountProduct> DiscountProducts => Set<DiscountProduct>();
    public DbSet<DiscountCategory> DiscountCategories => Set<DiscountCategory>();
    public DbSet<DiscountProductCategory> DiscountProductCategories => Set<DiscountProductCategory>();
    public DbSet<DiscountProductImage> DiscountProductImages => Set<DiscountProductImage>();
    public DbSet<DiscountShoppingCart> DiscountShoppingCarts => Set<DiscountShoppingCart>();
    public DbSet<DiscountOrder> DiscountOrders => Set<DiscountOrder>();
    public DbSet<DiscountOrderDetail> DiscountOrderDetails => Set<DiscountOrderDetail>();
    
    // ============= Geography DbSets =============
    public DbSet<Country> Countries => Set<Country>();
    public DbSet<State> States => Set<State>();
    public DbSet<City> Cities => Set<City>();
    
    // ============= Inventory Management DbSets =============
    public DbSet<Warehouse> Warehouses => Set<Warehouse>();
    public DbSet<InventoryItem> InventoryItems => Set<InventoryItem>();
    public DbSet<StockMovement> StockMovements => Set<StockMovement>();
    
    // ============= Blog DbSets =============
    public DbSet<BlogPost> BlogPosts => Set<BlogPost>();
    public DbSet<BlogCategory> BlogCategories => Set<BlogCategory>();
    public DbSet<BlogPostCategory> BlogPostCategories => Set<BlogPostCategory>();
    public DbSet<BlogPostTag> BlogPostTags => Set<BlogPostTag>();
    public DbSet<BlogPostImage> BlogPostImages => Set<BlogPostImage>();
    
    // ============= Content Management DbSets =============
    public DbSet<SitePage> SitePages => Set<SitePage>();
    public DbSet<SitePageSection> SitePageSections => Set<SitePageSection>();
    
    // ============= Site Page Settings (Simplified) =============
    public DbSet<SitePageSettings> SitePageSettingsEntities => Set<SitePageSettings>();
    public DbSet<SitePageImage> SitePageImages => Set<SitePageImage>();
}
