using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
using Health.Infrastructure.Data.Records;

namespace Health.Infrastructure.Data;

/// <summary>
/// 应用程序数据库上下文
/// </summary>
public sealed class AppDbContext(DbContextOptions<AppDbContext> options) : DbContext(options)
{

    // 核心业务表
    public DbSet<User> Users => Set<User>();
    public DbSet<HealthRecord> HealthRecords => Set<HealthRecord>();
    public DbSet<Medication> Medications => Set<Medication>();
    public DbSet<MedicationLog> MedicationLogs => Set<MedicationLog>();
    public DbSet<DietRecord> DietRecords => Set<DietRecord>();
    public DbSet<DietFoodItem> DietFoodItems => Set<DietFoodItem>();
    public DbSet<ExercisePlan> ExercisePlans => Set<ExercisePlan>();
    public DbSet<ExercisePlanItem> ExercisePlanItems => Set<ExercisePlanItem>();
    public DbSet<Report> Reports => Set<Report>();
    public DbSet<Conversation> Conversations => Set<Conversation>();
    public DbSet<ConversationMessage> ConversationMessages => Set<ConversationMessage>();
    public DbSet<Consultation> Consultations => Set<Consultation>();
    public DbSet<ConsultationMessage> ConsultationMessages => Set<ConsultationMessage>();
    public DbSet<Doctor> Doctors => Set<Doctor>();
    public DbSet<DoctorProfile> DoctorProfiles => Set<DoctorProfile>();
    public DbSet<FollowUp> FollowUps => Set<FollowUp>();
    public DbSet<HealthArchive> HealthArchives => Set<HealthArchive>();
    public DbSet<HealthArchiveSurgery> HealthArchiveSurgeries => Set<HealthArchiveSurgery>();

    // 支撑表
    public DbSet<RefreshToken> RefreshTokens => Set<RefreshToken>();
    public DbSet<VerificationCode> VerificationCodes => Set<VerificationCode>();
    public DbSet<NotificationPreference> NotificationPreferences => Set<NotificationPreference>();
    public DbSet<UserNotification> UserNotifications => Set<UserNotification>();
    public DbSet<DeviceToken> DeviceTokens => Set<DeviceToken>();
    public DbSet<AiWriteCommandRecord> AiWriteCommands => Set<AiWriteCommandRecord>();
    public DbSet<ReportAnalysisTaskRecord> ReportAnalysisTasks => Set<ReportAnalysisTaskRecord>();
    public DbSet<DietImageAnalysisTaskRecord> DietImageAnalysisTasks => Set<DietImageAnalysisTaskRecord>();
    public DbSet<MedicationReminderTaskRecord> MedicationReminderTasks => Set<MedicationReminderTaskRecord>();
    public DbSet<NotificationOutboxRecord> NotificationOutbox => Set<NotificationOutboxRecord>();

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

        // ---- User ----
        builder.Entity<User>(e =>
        {
            e.HasIndex(u => u.Phone).IsUnique();
            e.HasIndex(u => u.AppleUserId).IsUnique();  // Apple Sign-In 唯一标识
            e.Property(u => u.Role).HasMaxLength(32).HasDefaultValue("User");
            e.HasOne(u => u.Doctor).WithMany().HasForeignKey(u => u.DoctorId).IsRequired(false).OnDelete(DeleteBehavior.SetNull);
        });

        // ---- Doctor ----
        builder.Entity<Doctor>(e =>
        {
            e.Property(d => d.Phone).HasMaxLength(20);
            e.Property(d => d.ProfessionalDirection).HasMaxLength(256);
        });

        // ---- DoctorProfile ----
        builder.Entity<DoctorProfile>(e =>
        {
            e.HasIndex(d => d.UserId).IsUnique();
            e.HasOne(d => d.User).WithOne(u => u.DoctorProfile).HasForeignKey<DoctorProfile>(d => d.UserId);
            e.HasOne(d => d.Doctor).WithMany().HasForeignKey(d => d.DoctorId).IsRequired(false).OnDelete(DeleteBehavior.SetNull);
        });

        // ---- HealthRecord ----
        builder.Entity<HealthRecord>(e =>
        {
            e.HasIndex(r => new { r.UserId, r.RecordedAt }).IsDescending(false, true);
            e.HasIndex(r => new { r.UserId, r.MetricType });
            e.Property(r => r.MetricType).HasConversion<string>();
            e.Property(r => r.Source).HasConversion<string>();
        });

        // ---- Medication ----
        builder.Entity<Medication>(e =>
        {
            e.HasIndex(m => new { m.UserId, m.IsActive });
            e.Property(m => m.Frequency).HasConversion<string>();
            e.Property(m => m.Source).HasConversion<string>();
            e.Property(m => m.TimeOfDay).HasColumnType("time[]");
        });

        builder.Entity<MedicationLog>(e =>
        {
            e.HasIndex(l => new { l.MedicationId, l.CreatedAt }).IsDescending(false, true);
            e.Property(l => l.Status).HasConversion<string>();
        });

        // ---- Diet ----
        builder.Entity<DietRecord>(e =>
        {
            e.HasIndex(d => new { d.UserId, d.RecordedAt }).IsDescending(false, true);
            e.Property(d => d.MealType).HasConversion<string>();
        });

        // ---- ExercisePlan ----
        builder.Entity<ExercisePlan>(e =>
        {
            e.HasIndex(p => new { p.UserId, p.StartDate, p.EndDate });
        });

        builder.Entity<ExercisePlanItem>(e =>
        {
            e.HasIndex(i => new { i.PlanId, i.ScheduledDate }).IsUnique();
        });

        // ---- Report ----
        builder.Entity<Report>(e =>
        {
            e.Property(r => r.FileType).HasConversion<string>();
            e.Property(r => r.Category).HasConversion<string>();
            e.Property(r => r.Status).HasConversion<string>();
        });

        // ---- Conversation ----
        builder.Entity<Conversation>(e =>
        {
            e.HasIndex(c => new { c.UserId, c.UpdatedAt }).IsDescending(false, true);
            e.Property(c => c.AgentType).HasConversion<string>();
        });

        builder.Entity<ConversationMessage>(e =>
        {
            e.HasIndex(m => new { m.ConversationId, m.CreatedAt });
            e.Property(m => m.Role).HasConversion<string>();
        });

        // ---- Consultation ----
        builder.Entity<Consultation>(e =>
        {
            e.Property(c => c.Status).HasConversion<string>();
        });

        builder.Entity<ConsultationMessage>(e =>
        {
            e.HasIndex(m => new { m.ConsultationId, m.CreatedAt }).IsDescending(false, true);
            e.Property(m => m.SenderType).HasConversion<string>();
        });

        // ---- VerificationCode ----
        builder.Entity<VerificationCode>(e =>
        {
            e.HasIndex(v => new { v.Phone, v.CreatedAt }).IsDescending(false, true);
        });

        // ---- NotificationPreference ----
        builder.Entity<NotificationPreference>(e =>
        {
            e.HasIndex(n => n.UserId).IsUnique();
        });

        builder.Entity<UserNotification>(e =>
        {
            e.ToTable("UserNotifications");
            e.HasIndex(n => n.SourceId).IsUnique();
            e.HasIndex(n => new { n.UserId, n.IsDeleted, n.IsRead, n.CreatedAt });
            e.Property(n => n.Type).HasMaxLength(64);
            e.Property(n => n.Severity).HasMaxLength(16);
            e.Property(n => n.ActionType).HasMaxLength(64);
        });

        // ---- HealthArchive ----
        builder.Entity<HealthArchive>(e =>
        {
            e.HasIndex(a => a.UserId).IsUnique();
        });

        builder.Entity<HealthArchiveSurgery>(e =>
        {
            e.ToTable("HealthArchiveSurgeries");
            e.HasIndex(s => new { s.HealthArchiveId, s.SortOrder });
            e.Property(s => s.Type).HasMaxLength(256);
            e.HasOne(s => s.HealthArchive)
                .WithMany(a => a.Surgeries)
                .HasForeignKey(s => s.HealthArchiveId)
                .OnDelete(DeleteBehavior.Cascade);
        });

        builder.Entity<AiWriteCommandRecord>(e =>
        {
            e.ToTable("AiWriteCommands");
            e.HasIndex(x => new { x.UserId, x.Status, x.ExpiresAt });
            e.Property(x => x.ToolName).HasMaxLength(64);
            e.Property(x => x.Status).HasMaxLength(32);
            e.Property(x => x.Arguments).HasColumnType("jsonb");
        });

        builder.Entity<ReportAnalysisTaskRecord>(e =>
        {
            e.ToTable("ReportAnalysisTasks");
            e.HasIndex(x => new { x.Status, x.AvailableAt });
            e.HasIndex(x => x.ReportId);
            e.Property(x => x.Status).HasMaxLength(32);
        });

        builder.Entity<DietImageAnalysisTaskRecord>(e =>
        {
            e.ToTable("DietImageAnalysisTasks");
            e.HasIndex(x => new { x.Status, x.AvailableAt });
            e.Property(x => x.FilePaths).HasColumnType("jsonb");
            e.Property(x => x.Status).HasMaxLength(32);
        });

        builder.Entity<MedicationReminderTaskRecord>(e =>
        {
            e.ToTable("MedicationReminderTasks");
            e.HasIndex(x => new { x.Status, x.AvailableAt });
            e.HasIndex(x => new { x.MedicationId, x.ScheduledDate, x.ScheduledTime }).IsUnique();
            e.Property(x => x.Status).HasMaxLength(32);
        });

        builder.Entity<NotificationOutboxRecord>(e =>
        {
            e.ToTable("NotificationOutbox");
            e.HasIndex(x => x.SourceTaskId).IsUnique();
            e.HasIndex(x => new { x.Status, x.AvailableAt });
            e.Property(x => x.Type).HasMaxLength(64);
            e.Property(x => x.Status).HasMaxLength(32);
            e.Property(x => x.Payload).HasColumnType("jsonb");
        });
    }
}
