using LctMonolith.Models.Database;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;
using EventLog = LctMonolith.Models.Database.EventLog;
namespace LctMonolith.Database.Data;
///
/// Main EF Core database context for gamification module (PostgreSQL provider expected).
///
public class AppDbContext : IdentityDbContext, Guid>
{
public AppDbContext(DbContextOptions options) : base(options) {
Database.EnsureCreated();
}
// Rank related entities
public DbSet Ranks => Set();
public DbSet RankMissionRules => Set();
public DbSet RankSkillRules => Set();
// Mission related entities
public DbSet MissionCategories => Set();
public DbSet Missions => Set();
public DbSet PlayerMissions => Set();
public DbSet MissionSkillRewards => Set();
public DbSet MissionItemRewards => Set();
public DbSet MissionRankRules => Set();
// Skill related entities
public DbSet Skills => Set();
public DbSet PlayerSkills => Set();
// Dialogue related entities
public DbSet Dialogues => Set();
public DbSet DialogueMessages => Set();
public DbSet DialogueMessageResponseOptions => Set();
// Store and inventory
public DbSet StoreItems => Set();
public DbSet UserInventoryItems => Set();
public DbSet Transactions => Set();
// System entities
public DbSet EventLogs => Set();
public DbSet RefreshTokens => Set();
public DbSet Notifications => Set();
// Core profile / player chain
public DbSet Players => Set();
public DbSet Profiles => Set();
protected override void OnModelCreating(ModelBuilder b)
{
base.OnModelCreating(b);
// Player configuration
b.Entity()
.HasIndex(p => p.UserId)
.IsUnique();
b.Entity()
.HasOne()
.WithOne()
.HasForeignKey(p => p.UserId)
.IsRequired();
// Rank configurations
b.Entity()
.HasIndex(r => r.ExpNeeded)
.IsUnique();
b.Entity()
.HasIndex(r => r.Title)
.IsUnique();
// Skill configurations
b.Entity()
.HasIndex(s => s.Title)
.IsUnique();
// MissionCategory configurations
b.Entity()
.HasIndex(mc => mc.Title)
.IsUnique();
// Mission configurations
b.Entity()
.HasOne(m => m.MissionCategory)
.WithMany(mc => mc.Missions)
.HasForeignKey(m => m.MissionCategoryId)
.IsRequired();
b.Entity()
.HasOne(m => m.ParentMission)
.WithMany(m => m.ChildMissions)
.HasForeignKey(m => m.ParentMissionId)
.IsRequired(false);
// Dialogue relationship for Mission (optional dialogue for a mission)
b.Entity()
.HasOne(m => m.Dialogue)
.WithOne(d => d.Mission)
.HasForeignKey(m => m.DialogueId)
.IsRequired(false);
// MissionRankRule configurations
b.Entity()
.HasOne(mrr => mrr.Mission)
.WithMany(m => m.MissionRankRules)
.HasForeignKey(mrr => mrr.MissionId);
b.Entity()
.HasOne(mrr => mrr.Rank)
.WithMany(r => r.MissionRankRules)
.HasForeignKey(mrr => mrr.RankId);
// MissionSkillReward configurations
b.Entity()
.HasKey(x => new { x.MissionId, x.SkillId });
b.Entity()
.HasOne(msr => msr.Mission)
.WithMany(m => m.MissionSkillRewards)
.HasForeignKey(msr => msr.MissionId);
b.Entity()
.HasOne(msr => msr.Skill)
.WithMany(s => s.MissionSkillRewards)
.HasForeignKey(msr => msr.SkillId);
// MissionItemReward configurations
b.Entity()
.HasOne(mir => mir.Mission)
.WithMany(m => m.MissionItemRewards)
.HasForeignKey(mir => mir.MissionId);
// RankMissionRule composite key
b.Entity().HasKey(x => new { x.RankId, x.MissionId });
b.Entity()
.HasOne(rmr => rmr.Rank)
.WithMany(r => r.RankMissionRules)
.HasForeignKey(rmr => rmr.RankId);
b.Entity()
.HasOne(rmr => rmr.Mission)
.WithMany(m => m.RankMissionRules)
.HasForeignKey(rmr => rmr.MissionId);
// RankSkillRule composite key
b.Entity().HasKey(x => new { x.RankId, x.SkillId });
b.Entity()
.HasOne(rsr => rsr.Rank)
.WithMany(r => r.RankSkillRules)
.HasForeignKey(rsr => rsr.RankId);
b.Entity()
.HasOne(rsr => rsr.Skill)
.WithMany(s => s.RankSkillRules)
.HasForeignKey(rsr => rsr.SkillId);
// PlayerSkill composite key
b.Entity().HasKey(x => new { x.PlayerId, x.SkillId });
b.Entity()
.HasOne(ps => ps.Player)
.WithMany(p => p.PlayerSkills)
.HasForeignKey(ps => ps.PlayerId);
b.Entity()
.HasOne(ps => ps.Skill)
.WithMany(s => s.PlayerSkills)
.HasForeignKey(ps => ps.SkillId);
// PlayerMission composite key
b.Entity().HasKey(x => new { x.PlayerId, x.MissionId });
b.Entity()
.HasOne(pm => pm.Player)
.WithMany(p => p.PlayerMissions)
.HasForeignKey(pm => pm.PlayerId);
b.Entity()
.HasOne(pm => pm.Mission)
.WithMany(m => m.PlayerMissions)
.HasForeignKey(pm => pm.MissionId);
// Dialogue configurations (Mission required for Dialogue)
b.Entity()
.HasOne(d => d.Mission)
.WithOne(m => m.Dialogue)
.HasForeignKey(d => d.MissionId)
.IsRequired();
// Dialogue -> DialogueMessage relationships (three distinct message slots)
b.Entity()
.HasOne(d => d.InitialDialogueMessage)
.WithMany()
.HasForeignKey(d => d.InitialDialogueMessageId)
.OnDelete(DeleteBehavior.Restrict);
b.Entity()
.HasOne(d => d.InterimDialogueMessage)
.WithMany()
.HasForeignKey(d => d.InterimDialogueMessageId)
.OnDelete(DeleteBehavior.Restrict);
b.Entity()
.HasOne(d => d.EndDialogueMessage)
.WithMany()
.HasForeignKey(d => d.EndDialogueMessageId)
.OnDelete(DeleteBehavior.Restrict);
// DialogueMessageResponseOption configurations
b.Entity()
.HasOne(dmro => dmro.ParentDialogueMessage)
.WithMany(dm => dm.DialogueMessageResponseOptions)
.HasForeignKey(dmro => dmro.ParentDialogueMessageId)
.IsRequired();
b.Entity()
.HasOne(dmro => dmro.DestinationDialogueMessage)
.WithMany()
.HasForeignKey(dmro => dmro.DestinationDialogueMessageId)
.IsRequired(false)
.OnDelete(DeleteBehavior.Restrict);
// UserInventoryItem composite key & relationships
b.Entity()
.HasKey(ui => new { ui.UserId, ui.StoreItemId });
b.Entity()
.HasOne(ui => ui.User)
.WithMany(u => u.Inventory)
.HasForeignKey(ui => ui.UserId);
b.Entity()
.HasOne(ui => ui.StoreItem)
.WithMany(si => si.UserInventory)
.HasForeignKey(ui => ui.StoreItemId);
// Refresh token index unique
b.Entity().HasIndex(x => x.Token).IsUnique();
// ---------- Performance indexes ----------
b.Entity().HasIndex(ps => ps.SkillId);
b.Entity().HasIndex(e => new { e.UserId, e.Type, e.CreatedAt });
b.Entity().HasIndex(i => i.IsActive);
b.Entity().HasIndex(t => new { t.UserId, t.CreatedAt });
b.Entity().HasIndex(n => new { n.UserId, n.IsRead, n.CreatedAt });
}
}