using System.Text.Json;
using Meezi.Core.Entities;
using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.ChangeTracking;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;

namespace Meezi.Infrastructure.Data;

public class AppDbContext : DbContext
{
    public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
    {
    }

    public DbSet<Cafe> Cafes => Set<Cafe>();
    public DbSet<Branch> Branches => Set<Branch>();
    public DbSet<Table> Tables => Set<Table>();
    public DbSet<TableSection> TableSections => Set<TableSection>();
    public DbSet<Employee> Employees => Set<Employee>();
    public DbSet<MenuCategory> MenuCategories => Set<MenuCategory>();
    public DbSet<MenuItem> MenuItems => Set<MenuItem>();
    public DbSet<BranchMenuItemOverride> BranchMenuItemOverrides => Set<BranchMenuItemOverride>();
    public DbSet<Order> Orders => Set<Order>();
    public DbSet<OrderItem> OrderItems => Set<OrderItem>();
    public DbSet<Payment> Payments => Set<Payment>();
    public DbSet<Customer> Customers => Set<Customer>();
    public DbSet<Coupon> Coupons => Set<Coupon>();
    public DbSet<Tax> Taxes => Set<Tax>();
    public DbSet<EmployeeSalary> EmployeeSalaries => Set<EmployeeSalary>();
    public DbSet<Attendance> Attendances => Set<Attendance>();
    public DbSet<EmployeeSchedule> EmployeeSchedules => Set<EmployeeSchedule>();
    public DbSet<Shift> RegisterShifts => Set<Shift>();
    public DbSet<CashTransaction> CashTransactions => Set<CashTransaction>();
    public DbSet<LeaveRequest> LeaveRequests => Set<LeaveRequest>();
    public DbSet<TableReservation> TableReservations => Set<TableReservation>();
    public DbSet<CafeReview> CafeReviews => Set<CafeReview>();
    public DbSet<CafeReviewPhoto> CafeReviewPhotos => Set<CafeReviewPhoto>();
    public DbSet<ConsumerAccount> ConsumerAccounts => Set<ConsumerAccount>();
    public DbSet<KitchenStation> KitchenStations => Set<KitchenStation>();
    public DbSet<SubscriptionPayment> SubscriptionPayments => Set<SubscriptionPayment>();
    public DbSet<Ingredient> Ingredients => Set<Ingredient>();
    public DbSet<MenuItemIngredient> MenuItemIngredients => Set<MenuItemIngredient>();
    public DbSet<StockMovement> StockMovements => Set<StockMovement>();
    public DbSet<QueueTicket> QueueTickets => Set<QueueTicket>();
    public DbSet<DailyReport> DailyReports => Set<DailyReport>();
    public DbSet<Expense> Expenses => Set<Expense>();
    public DbSet<WebhookLog> WebhookLogs => Set<WebhookLog>();
    public DbSet<DeliveryCommissionRate> DeliveryCommissionRates => Set<DeliveryCommissionRate>();
    public DbSet<SystemAdmin> SystemAdmins => Set<SystemAdmin>();
    public DbSet<PlatformPlanDefinition> PlatformPlanDefinitions => Set<PlatformPlanDefinition>();
    public DbSet<PlatformSetting> PlatformSettings => Set<PlatformSetting>();
    public DbSet<PlatformFeature> PlatformFeatures => Set<PlatformFeature>();
    public DbSet<CafeFeatureOverride> CafeFeatureOverrides => Set<CafeFeatureOverride>();
    public DbSet<SupportTicket> SupportTickets => Set<SupportTicket>();
    public DbSet<SupportTicketMessage> SupportTicketMessages => Set<SupportTicketMessage>();
    public DbSet<CafeNotification> CafeNotifications => Set<CafeNotification>();

    // Website CMS
    public DbSet<WebsiteBlogPost> WebsiteBlogPosts => Set<WebsiteBlogPost>();
    public DbSet<WebsiteComment> WebsiteComments => Set<WebsiteComment>();
    public DbSet<DemoRequest> DemoRequests => Set<DemoRequest>();

    // Push notifications (Pushe)
    public DbSet<PushDevice> PushDevices => Set<PushDevice>();

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

        modelBuilder.Entity<PushDevice>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => x.Token).IsUnique();
            e.HasIndex(x => x.City);
            e.Property(x => x.Token).HasMaxLength(256).IsRequired();
            e.Property(x => x.Platform).HasMaxLength(20).IsRequired();
            e.Property(x => x.City).HasMaxLength(100);
            e.Property(x => x.ConsumerAccountId).HasMaxLength(64);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Cafe>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => x.Slug).IsUnique();
            e.Property(x => x.Name).HasMaxLength(200).IsRequired();
            e.Property(x => x.Slug).HasMaxLength(100).IsRequired();
            e.Property(x => x.SnappfoodVendorId).HasMaxLength(100);
            e.Property(x => x.Tap30VendorId).HasMaxLength(100);
            e.Property(x => x.DigikalaVendorId).HasMaxLength(100);
            e.Property(x => x.ThemeJson).HasMaxLength(8000);
            e.Property(x => x.DiscoverProfileJson).HasMaxLength(8000);
            e.Property(x => x.DiscoverBadgesJson).HasMaxLength(2000);
            e.Property(x => x.DefaultTaxRate).HasPrecision(5, 2);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Branch>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Name).HasMaxLength(200).IsRequired();
            e.Property(x => x.Address).HasMaxLength(500);
            e.Property(x => x.City).HasMaxLength(100);
            e.Property(x => x.Phone).HasMaxLength(20);
            e.Property(x => x.ReceiptPrinterIp).HasMaxLength(45);
            e.Property(x => x.KitchenPrinterIp).HasMaxLength(45);
            e.Property(x => x.PosDeviceIp).HasMaxLength(45);
            e.Property(x => x.ReceiptHeader).HasMaxLength(500);
            e.Property(x => x.ReceiptFooter).HasMaxLength(500);
            e.Property(x => x.WifiPassword).HasMaxLength(100);
            e.HasIndex(x => new { x.CafeId, x.IsActive });
            e.HasOne(x => x.Cafe).WithMany(c => c.Branches).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<TableSection>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Name).HasMaxLength(100).IsRequired();
            e.HasIndex(x => new { x.BranchId, x.Name });
            e.HasIndex(x => x.CafeId);
            e.HasOne(x => x.Branch).WithMany(b => b.Sections).HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Table>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Number).HasMaxLength(50).IsRequired();
            e.Property(x => x.BranchId).IsRequired();
            e.Property(x => x.SortOrder).HasDefaultValue(0);
            e.HasIndex(x => x.QrCode).IsUnique();
            e.HasIndex(x => new { x.BranchId, x.SectionId, x.SortOrder });
            e.HasOne(x => x.Cafe).WithMany(c => c.Tables).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany(b => b.Tables).HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.Restrict);
            e.HasOne(x => x.Section).WithMany(s => s.Tables).HasForeignKey(x => x.SectionId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Employee>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.Phone })
                .IsUnique()
                .HasFilter("\"DeletedAt\" IS NULL");
            e.HasIndex(x => x.BranchId);
            e.HasOne(x => x.Cafe).WithMany(c => c.Employees).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany(b => b.Staff).HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<MenuCategory>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Icon).HasMaxLength(32);
            e.Property(x => x.IconPresetId).HasMaxLength(48);
            e.Property(x => x.IconStyle).HasMaxLength(16);
            e.Property(x => x.ImageUrl).HasMaxLength(500);
            e.HasOne(x => x.Cafe).WithMany(c => c.MenuCategories).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Tax).WithMany(t => t.MenuCategories).HasForeignKey(x => x.TaxId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.KitchenStation).WithMany(s => s.Categories).HasForeignKey(x => x.KitchenStationId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<MenuItem>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Model3dUrl).HasMaxLength(500);
            e.Property(x => x.Price).HasPrecision(18, 2);
            e.HasOne(x => x.Cafe).WithMany(c => c.MenuItems).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Category).WithMany(c => c.MenuItems).HasForeignKey(x => x.CategoryId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<BranchMenuItemOverride>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.PriceOverride).HasPrecision(18, 2);
            e.HasIndex(x => new { x.BranchId, x.MenuItemId }).IsUnique();
            e.HasIndex(x => x.CafeId);
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.MenuItem).WithMany(m => m.BranchOverrides).HasForeignKey(x => x.MenuItemId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Order>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Subtotal).HasPrecision(18, 2);
            e.Property(x => x.TaxTotal).HasPrecision(18, 2);
            e.Property(x => x.Total).HasPrecision(18, 2);
            e.Property(x => x.DiscountAmount).HasPrecision(18, 2);
            e.Property(x => x.PlatformCommission).HasPrecision(18, 2);
            e.Property(x => x.ExternalOrderId).HasMaxLength(120);
            e.Property(x => x.DeliveryMetaJson).HasMaxLength(4000);
            e.Property(x => x.GuestTrackingToken).HasMaxLength(64);
            e.HasIndex(x => x.GuestTrackingToken);
            e.HasIndex(x => new { x.CafeId, x.DisplayNumber }).IsUnique();
            e.HasIndex(x => new { x.CafeId, x.DeliveryPlatform, x.ExternalOrderId });
            e.HasOne(x => x.Cafe).WithMany(c => c.Orders).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany(b => b.Orders).HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Table).WithMany(t => t.Orders).HasForeignKey(x => x.TableId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Reservation).WithMany().HasForeignKey(x => x.ReservationId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Customer).WithMany(c => c.Orders).HasForeignKey(x => x.CustomerId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Employee).WithMany(emp => emp.Orders).HasForeignKey(x => x.EmployeeId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Coupon).WithMany(c => c.Orders).HasForeignKey(x => x.CouponId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<OrderItem>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.UnitPrice).HasPrecision(18, 2);
            e.HasOne(x => x.Order).WithMany(o => o.Items).HasForeignKey(x => x.OrderId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.MenuItem).WithMany(m => m.OrderItems).HasForeignKey(x => x.MenuItemId).OnDelete(DeleteBehavior.Restrict);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Payment>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Amount).HasPrecision(18, 2);
            e.HasOne(x => x.Order).WithMany(o => o.Payments).HasForeignKey(x => x.OrderId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Customer>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.Phone });
            e.HasOne(x => x.Cafe).WithMany(c => c.Customers).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Coupon>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.Code }).IsUnique();
            e.Property(x => x.Value).HasPrecision(18, 2);
            e.HasOne(x => x.Cafe).WithMany(c => c.Coupons).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Tax>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Rate).HasPrecision(5, 2);
            e.HasOne(x => x.Cafe).WithMany(c => c.Taxes).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<EmployeeSalary>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.EmployeeId, x.MonthYear }).IsUnique();
            e.HasOne(x => x.Employee).WithMany(e => e.Salaries).HasForeignKey(x => x.EmployeeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Attendance>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.EmployeeId, x.Date }).IsUnique();
            e.HasOne(x => x.Employee).WithMany(e => e.Attendances).HasForeignKey(x => x.EmployeeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<EmployeeSchedule>(e =>
        {
            e.HasKey(x => x.Id);
            e.ToTable("EmployeeSchedules");
            e.HasIndex(x => new { x.EmployeeId, x.DayOfWeek }).IsUnique();
            e.HasOne(x => x.Employee).WithMany(e => e.Schedules).HasForeignKey(x => x.EmployeeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Shift>(e =>
        {
            e.HasKey(x => x.Id);
            e.ToTable("RegisterShifts");
            e.Property(x => x.OpeningCash).HasPrecision(18, 2);
            e.Property(x => x.ClosingCash).HasPrecision(18, 2);
            e.Property(x => x.ExpectedCash).HasPrecision(18, 2);
            e.Property(x => x.Discrepancy).HasPrecision(18, 2);
            e.HasIndex(x => new { x.BranchId, x.Status });
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.OpenedBy).WithMany().HasForeignKey(x => x.OpenedByUserId).OnDelete(DeleteBehavior.Restrict);
            e.HasOne(x => x.ClosedBy).WithMany().HasForeignKey(x => x.ClosedByUserId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<CashTransaction>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Amount).HasPrecision(18, 2);
            e.HasIndex(x => x.ShiftId);
            e.HasIndex(x => new { x.CafeId, x.BranchId });
            e.HasOne(x => x.Shift).WithMany(s => s.Transactions).HasForeignKey(x => x.ShiftId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<LeaveRequest>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasOne(x => x.Employee).WithMany(e => e.LeaveRequests).HasForeignKey(x => x.EmployeeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<TableReservation>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.Date, x.Time });
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Table).WithMany().HasForeignKey(x => x.TableId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Customer).WithMany().HasForeignKey(x => x.CustomerId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<CafeReview>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.CreatedAt });
            e.Property(x => x.AuthorName).HasMaxLength(200).IsRequired();
            e.HasOne(x => x.Cafe).WithMany(c => c.Reviews).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<CafeReviewPhoto>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Url).HasMaxLength(500).IsRequired();
            e.HasIndex(x => x.ReviewId);
            e.HasOne(x => x.Review).WithMany(r => r.Photos).HasForeignKey(x => x.ReviewId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<ConsumerAccount>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Phone).HasMaxLength(20).IsRequired();
            e.HasIndex(x => x.Phone).IsUnique();
            e.Property(x => x.Name).HasMaxLength(200);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<KitchenStation>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Name).HasMaxLength(100).IsRequired();
            e.Property(x => x.PrinterIp).HasMaxLength(45);
            e.HasIndex(x => new { x.CafeId, x.SortOrder });
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<SubscriptionPayment>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => x.Authority);
            e.Property(x => x.AmountToman).HasPrecision(18, 2);
            e.HasOne(x => x.Cafe).WithMany(c => c.SubscriptionPayments).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Ingredient>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Name).HasMaxLength(200).IsRequired();
            e.Property(x => x.Unit).HasMaxLength(50).IsRequired();
            e.Property(x => x.QuantityOnHand).HasPrecision(18, 3);
            e.Property(x => x.ReorderLevel).HasPrecision(18, 3);
            e.Property(x => x.UnitCost).HasPrecision(18, 2);
            e.Property(x => x.ParLevel).HasPrecision(18, 3);
            e.Property(x => x.LowStockWarningPercent).HasPrecision(5, 2);
            e.HasOne(x => x.Cafe).WithMany(c => c.Ingredients).HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<MenuItemIngredient>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.QuantityPerUnit).HasPrecision(18, 3);
            e.HasIndex(x => new { x.CafeId, x.MenuItemId, x.IngredientId }).IsUnique();
            e.HasOne(x => x.MenuItem).WithMany(m => m.RecipeIngredients).HasForeignKey(x => x.MenuItemId)
                .OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Ingredient).WithMany(i => i.MenuItemRecipes).HasForeignKey(x => x.IngredientId)
                .OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<StockMovement>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Delta).HasPrecision(18, 3);
            e.Property(x => x.TotalCostToman).HasPrecision(18, 2);
            e.Property(x => x.ExpenseId).HasMaxLength(64);
            e.Property(x => x.BranchId).HasMaxLength(64);
            e.Property(x => x.Kind).HasConversion<string>().HasMaxLength(30);
            e.Property(x => x.OrderId).HasMaxLength(64);
            e.HasIndex(x => new { x.CafeId, x.OrderId });
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Ingredient).WithMany(i => i.Movements).HasForeignKey(x => x.IngredientId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<QueueTicket>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.BranchId, x.ServiceDate, x.Number }).IsUnique();
            e.Property(x => x.CustomerLabel).HasMaxLength(200);
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.SetNull);
            e.HasOne(x => x.Order).WithMany().HasForeignKey(x => x.OrderId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<Expense>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Amount).HasPrecision(18, 2);
            e.Property(x => x.Note).HasMaxLength(500);
            e.Property(x => x.ReceiptImageUrl).HasMaxLength(500);
            e.HasIndex(x => new { x.CafeId, x.BranchId, x.CreatedAt });
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.Shift).WithMany().HasForeignKey(x => x.ShiftId).OnDelete(DeleteBehavior.SetNull);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<DailyReport>(e =>
        {
            e.HasKey(x => x.Id);
            e.HasIndex(x => new { x.CafeId, x.BranchId, x.Date }).IsUnique();
            e.Property(x => x.TotalRevenue).HasPrecision(18, 2);
            e.Property(x => x.CashRevenue).HasPrecision(18, 2);
            e.Property(x => x.CardRevenue).HasPrecision(18, 2);
            e.Property(x => x.CreditRevenue).HasPrecision(18, 2);
            e.Property(x => x.AvgOrderValue).HasPrecision(18, 2);
            e.Property(x => x.VoidAmount).HasPrecision(18, 2);
            e.Property(x => x.TotalExpenses).HasPrecision(18, 2);
            e.Property(x => x.NetIncome).HasPrecision(18, 2);
            var topProductsConverter = new ValueConverter<List<TopProductEntry>, string>(
                v => JsonSerializer.Serialize(v, JsonSerializerOptions.Default),
                v => JsonSerializer.Deserialize<List<TopProductEntry>>(v, JsonSerializerOptions.Default)
                    ?? new List<TopProductEntry>());
            var topProductsComparer = new ValueComparer<List<TopProductEntry>>(
                (a, b) => JsonSerializer.Serialize(a, JsonSerializerOptions.Default)
                    == JsonSerializer.Serialize(b, JsonSerializerOptions.Default),
                v => JsonSerializer.Serialize(v, JsonSerializerOptions.Default).GetHashCode(),
                v => JsonSerializer.Deserialize<List<TopProductEntry>>(
                    JsonSerializer.Serialize(v, JsonSerializerOptions.Default),
                    JsonSerializerOptions.Default)!);

            e.Property(x => x.TopProducts)
                .HasConversion(topProductsConverter, topProductsComparer)
                .HasColumnType("jsonb");
            e.HasOne(x => x.Branch).WithMany().HasForeignKey(x => x.BranchId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<WebhookLog>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.RawBody).IsRequired();
            e.Property(x => x.SignatureHeader).HasMaxLength(256);
            e.Property(x => x.ErrorMessage).HasMaxLength(2000);
            e.Property(x => x.ExternalOrderId).HasMaxLength(120);
            e.Property(x => x.MeeziOrderId).HasMaxLength(50);
            e.HasIndex(x => new { x.Platform, x.CreatedAt });
            e.HasIndex(x => x.CafeId);
        });

        modelBuilder.Entity<DeliveryCommissionRate>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.RatePercent).HasPrecision(5, 2);
            e.HasIndex(x => new { x.CafeId, x.Platform }).IsUnique();
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<SystemAdmin>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Name).HasMaxLength(200).IsRequired();
            e.Property(x => x.Phone).HasMaxLength(20).IsRequired();
            e.HasIndex(x => x.Phone).IsUnique();
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<PlatformPlanDefinition>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.DisplayNameFa).HasMaxLength(200).IsRequired();
            e.Property(x => x.DisplayNameEn).HasMaxLength(200);
            e.Property(x => x.MonthlyPriceToman).HasPrecision(18, 0);
            e.Property(x => x.LimitsJson).HasMaxLength(4000).IsRequired();
            e.Property(x => x.FeaturesJson).HasMaxLength(4000);
            e.HasIndex(x => x.Tier).IsUnique();
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<PlatformSetting>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Key).HasMaxLength(120).IsRequired();
            e.Property(x => x.Value).HasMaxLength(8000).IsRequired();
            e.Property(x => x.Category).HasMaxLength(60).IsRequired();
            e.Property(x => x.DescriptionFa).HasMaxLength(500);
            e.HasIndex(x => x.Key).IsUnique();
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<PlatformFeature>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Key).HasMaxLength(80).IsRequired();
            e.Property(x => x.DisplayNameFa).HasMaxLength(200).IsRequired();
            e.Property(x => x.DisplayNameEn).HasMaxLength(200);
            e.Property(x => x.ModuleGroup).HasMaxLength(60).IsRequired();
            e.HasIndex(x => x.Key).IsUnique();
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<CafeFeatureOverride>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.FeatureKey).HasMaxLength(80).IsRequired();
            e.HasIndex(x => new { x.CafeId, x.FeatureKey }).IsUnique();
            e.HasOne<Cafe>().WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<SupportTicket>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Subject).HasMaxLength(300).IsRequired();
            e.HasIndex(x => new { x.CafeId, x.Status, x.UpdatedAt });
            e.HasOne(x => x.Cafe).WithMany().HasForeignKey(x => x.CafeId).OnDelete(DeleteBehavior.Cascade);
            e.HasOne(x => x.CreatedByEmployee).WithMany().HasForeignKey(x => x.CreatedByEmployeeId)
                .OnDelete(DeleteBehavior.Restrict);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<SupportTicketMessage>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Body).HasMaxLength(8000).IsRequired();
            e.HasIndex(x => new { x.TicketId, x.CreatedAt });
            e.HasOne(x => x.Ticket).WithMany(t => t.Messages).HasForeignKey(x => x.TicketId)
                .OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<CafeNotification>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Type).HasMaxLength(60).IsRequired();
            e.Property(x => x.Title).HasMaxLength(300).IsRequired();
            e.Property(x => x.Body).HasMaxLength(1000);
            e.Property(x => x.ReferenceId).HasMaxLength(64);
            e.Property(x => x.TableNumber).HasMaxLength(40);
            e.HasIndex(x => new { x.CafeId, x.IsRead, x.CreatedAt });
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        // ── Website CMS ──────────────────────────────────────────────────────
        modelBuilder.Entity<WebsiteBlogPost>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.Slug).HasMaxLength(200).IsRequired();
            e.Property(x => x.TitleFa).HasMaxLength(400).IsRequired();
            e.Property(x => x.TitleEn).HasMaxLength(400);
            e.Property(x => x.ExcerptFa).HasMaxLength(1000);
            e.Property(x => x.ExcerptEn).HasMaxLength(1000);
            e.Property(x => x.ContentFa).HasColumnType("text");
            e.Property(x => x.ContentEn).HasColumnType("text");
            e.Property(x => x.Author).HasMaxLength(200);
            e.Property(x => x.CategoryFa).HasMaxLength(100);
            e.Property(x => x.CategoryEn).HasMaxLength(100);
            e.Property(x => x.TagsJson).HasMaxLength(2000).HasDefaultValue("[]");
            e.Property(x => x.CoverImage).HasMaxLength(500);
            e.HasIndex(x => x.Slug).IsUnique();
            e.HasIndex(x => new { x.IsPublished, x.PublishedAt });
            e.HasMany(x => x.Comments).WithOne(c => c.Post).HasForeignKey(c => c.PostSlug)
                .HasPrincipalKey(p => p.Slug).OnDelete(DeleteBehavior.Cascade);
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<WebsiteComment>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.PostSlug).HasMaxLength(200).IsRequired();
            e.Property(x => x.AuthorName).HasMaxLength(100).IsRequired();
            e.Property(x => x.AuthorEmail).HasMaxLength(200);
            e.Property(x => x.Content).HasMaxLength(3000).IsRequired();
            e.Property(x => x.IpAddress).HasMaxLength(50);
            e.HasIndex(x => new { x.PostSlug, x.IsApproved, x.CreatedAt });
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

        modelBuilder.Entity<DemoRequest>(e =>
        {
            e.HasKey(x => x.Id);
            e.Property(x => x.ContactName).HasMaxLength(200).IsRequired();
            e.Property(x => x.BusinessName).HasMaxLength(300).IsRequired();
            e.Property(x => x.Phone).HasMaxLength(20).IsRequired();
            e.Property(x => x.Email).HasMaxLength(200);
            e.Property(x => x.BranchCount).HasMaxLength(20);
            e.Property(x => x.Notes).HasMaxLength(2000);
            e.Property(x => x.Source).HasMaxLength(50).HasDefaultValue("website");
            e.Property(x => x.AdminNotes).HasMaxLength(2000);
            e.HasIndex(x => new { x.Status, x.CreatedAt });
            e.HasQueryFilter(x => x.DeletedAt == null);
        });

    }
}
