using Jiaowu.Api.Domain.Common;

namespace Jiaowu.Api.Domain.Academic;

public sealed class GradeSheet : EntityBase
{
    public Guid TeachingTaskId { get; set; }
    public TeachingTask? TeachingTask { get; set; }
    public decimal RegularWeight { get; set; } = 30;
    public decimal FinalWeight { get; set; } = 70;
    public GradeSheetStatus Status { get; set; } = GradeSheetStatus.Draft;
    public string? ReviewComment { get; set; }
    public DateTime? SubmittedAt { get; set; }
    public DateTime? ReviewedAt { get; set; }
    public DateTime? PublishedAt { get; set; }
    public ICollection<GradeRecord> Records { get; set; } = [];
    public ICollection<GradeItem> Items { get; set; } = [];
}

public sealed class GradeItem : EntityBase
{
    public Guid GradeSheetId { get; set; }
    public GradeSheet? GradeSheet { get; set; }
    public required string Name { get; set; }
    public decimal Weight { get; set; }
    public int SortOrder { get; set; }
    public GradeItemSourceType SourceType { get; set; } =
        GradeItemSourceType.Manual;
    public DateTime? SourceSnapshotAt { get; set; }
    public ICollection<GradeItemScore> Scores { get; set; } = [];
}

public sealed class GradeRecord : EntityBase
{
    public Guid GradeSheetId { get; set; }
    public GradeSheet? GradeSheet { get; set; }
    public Guid StudentId { get; set; }
    public Student? Student { get; set; }
    public decimal? RegularScore { get; set; }
    public decimal? FinalScore { get; set; }
    public decimal? TotalScore { get; set; }
    public decimal? GradePoint { get; set; }
    public GradeExamStatus ExamStatus { get; set; } = GradeExamStatus.Normal;
    public string? Notes { get; set; }
    public ICollection<GradeItemScore> ItemScores { get; set; } = [];
}

public sealed class GradeItemScore
{
    public Guid GradeRecordId { get; set; }
    public GradeRecord? GradeRecord { get; set; }
    public Guid GradeItemId { get; set; }
    public GradeItem? GradeItem { get; set; }
    public decimal? Score { get; set; }
}

/// <summary>
/// Persisted course-result aggregate.  One course/term is materialized at each
/// organizational level so the result-analysis page never aggregates raw
/// grade records on request.
/// </summary>
public sealed class CourseGradeStatistic : EntityBase
{
    public Guid CourseId { get; set; }
    public Guid AcademicTermId { get; set; }
    public CourseGradeStatisticScope Scope { get; set; }
    public Guid? ScopeEntityId { get; set; }
    public int StudentCount { get; set; }
    public int PassedCount { get; set; }
    public int Below60Count { get; set; }
    public int From60To69Count { get; set; }
    public int From70To79Count { get; set; }
    public int From80To89Count { get; set; }
    public int From90To100Count { get; set; }
    public decimal HighestScore { get; set; }
    public decimal AverageScore { get; set; }
    public decimal LowestScore { get; set; }
    public decimal PassRate { get; set; }
    public DateTime CalculatedAt { get; set; }
}

/// <summary>
/// Materialized analysis for one published teaching class. Course/term
/// organizational benchmarks stay in <see cref="CourseGradeStatistic"/>;
/// this table is the grain used for peer-class and historical comparisons.
/// </summary>
public sealed class TeachingTaskGradeStatistic : EntityBase
{
    public Guid GradeSheetId { get; set; }
    public GradeSheet? GradeSheet { get; set; }
    public Guid TeachingTaskId { get; set; }
    public TeachingTask? TeachingTask { get; set; }
    public Guid CourseId { get; set; }
    public Guid AcademicTermId { get; set; }
    public int StudentCount { get; set; }
    public int PassedCount { get; set; }
    public int ExcellentCount { get; set; }
    public decimal HighestScore { get; set; }
    public decimal AverageScore { get; set; }
    public decimal MedianScore { get; set; }
    public decimal LowestScore { get; set; }
    public decimal StandardDeviation { get; set; }
    public decimal PassRate { get; set; }
    public decimal ExcellentRate { get; set; }
    public DateTime CalculatedAt { get; set; }
    public ICollection<TeachingTaskGradeScoreBand> ScoreBands { get; set; } = [];
}

/// <summary>
/// Flexible score-band rows are kept separately so future band definitions do
/// not require widening the teaching-class summary table.
/// </summary>
public sealed class TeachingTaskGradeScoreBand : EntityBase
{
    public Guid TeachingTaskGradeStatisticId { get; set; }
    public TeachingTaskGradeStatistic? TeachingTaskGradeStatistic { get; set; }
    public required string Label { get; set; }
    public decimal LowerBound { get; set; }
    public decimal? UpperBound { get; set; }
    public int StudentCount { get; set; }
    public int SortOrder { get; set; }
}

public enum CourseGradeStatisticScope
{
    AdministrativeClass = 1,
    Major = 2,
    College = 3,
    University = 4
}

public sealed class CourseGradeStatisticsRefreshJob : EntityBase
{
    public Guid GradeSheetId { get; set; }
    public CourseGradeStatisticsRefreshJobStatus Status { get; set; } =
        CourseGradeStatisticsRefreshJobStatus.Queued;
    public DateTime? StartedAt { get; set; }
    public DateTime? CompletedAt { get; set; }
    public string? ErrorMessage { get; set; }
}

public enum CourseGradeStatisticsRefreshJobStatus
{
    Queued = 1,
    Running = 2,
    Succeeded = 3,
    Failed = 4
}

public enum GradeSheetStatus
{
    Draft = 1,
    Submitted = 2,
    Approved = 3,
    Published = 4,
    Returned = 5
}

public enum GradeExamStatus
{
    Normal = 1,
    Absent = 2,
    Deferred = 3,
    Exempt = 4,
    Makeup = 5
}

public enum GradeItemSourceType
{
    Manual = 1,
    ExperimentSummary = 2
}
