using System.Globalization;
using System.Security.Cryptography;
using System.Text.Json.Nodes;
using Eis.Application.Administration;
using Eis.Application.Public;
using Eis.Infrastructure.Authentication;
using Eis.Infrastructure.Candidate;
using Eis.Infrastructure.Security;

namespace Eis.Infrastructure.Administration;

internal sealed partial class AdminAdmissionService(
    IAuthenticationStateStore authenticationState,
    AuthenticationRepository authenticationRepository,
    PasswordCompatibilityService passwords,
    CandidateAdmissionRepository admissionRepository,
    AdminOperationalSnapshotLoader operationalLoader,
    AdminAccountBatchSnapshotLoader directoryLoader,
    AdminWorkflowResultSnapshotLoader resultLoader,
    AdminAdmissionRepository repository,
    DocumentVerificationCodeService documentCodes,
    IPublicQueryService publicQueries) : IAdminAdmissionService
{
    private static readonly HashSet<string> Phases =
        ["draft", "filling", "closed", "matching", "school_review", "reporting", "supplementary", "completed"];
    private static readonly IReadOnlyDictionary<string, string[]> SpecialtyTypes =
        new Dictionary<string, string[]>(StringComparer.Ordinal)
        {
            ["sports"] =
            [
                "track_field", "basketball", "football", "volleyball", "table_tennis", "badminton",
                "swimming", "martial_arts", "aerobics_cheer"
            ],
            ["arts"] =
            [
                "vocal_music", "instrumental_music", "dance", "fine_arts", "calligraphy",
                "drama_broadcasting"
            ]
        };
    private static readonly IReadOnlyDictionary<string, (string Category, string Type)> LegacySpecialties =
        new Dictionary<string, (string Category, string Type)>(StringComparer.Ordinal)
        {
            ["田径"] = ("sports", "track_field"),
            ["篮球"] = ("sports", "basketball"),
            ["足球"] = ("sports", "football"),
            ["排球"] = ("sports", "volleyball"),
            ["乒乓球"] = ("sports", "table_tennis"),
            ["羽毛球"] = ("sports", "badminton"),
            ["游泳"] = ("sports", "swimming"),
            ["武术"] = ("sports", "martial_arts"),
            ["健美操与啦啦操"] = ("sports", "aerobics_cheer"),
            ["声乐"] = ("arts", "vocal_music"),
            ["器乐"] = ("arts", "instrumental_music"),
            ["舞蹈"] = ("arts", "dance"),
            ["美术"] = ("arts", "fine_arts"),
            ["书法"] = ("arts", "calligraphy"),
            ["戏剧与播音"] = ("arts", "drama_broadcasting")
        };

    public async Task<AdminEndpointResult> GetAsync(string sessionToken, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以查看志愿与录取数据", cancellationToken);
        if (context.Error is not null) return context.Error;
        var data = await LoadAsync(cancellationToken);
        var settings = Records(data, "setting").Select(item =>
        {
            var output = RecordJson(item);
            output["exam"] = data.Operational.Exams.FirstOrDefault(exam => exam.Id == item.ExamId)?.Data.DeepClone();
            return output;
        }).ToArray();
        var plans = Records(data, "plan").Select(item =>
        {
            var output = RecordJson(item);
            output["schoolName"] = School(data, item.SchoolId)?.Name ?? "";
            output["examName"] = data.Operational.Exams.FirstOrDefault(exam => exam.Id == item.ExamId)?.Data["name"]?.GetValue<string>() ?? "";
            output["remainingCategories"] = RemainingPlanQuota(data, item);
            output["progress"] = PlanProgress(data, item);
            return output;
        }).ToArray();
        var preferences = Records(data, "preference").Select(item => PreferenceJson(data, item)).ToArray();
        var placements = Records(data, "placement").Select(item => PlacementJson(data, item)).ToArray();
        var reporting = Records(data, "notification")
            .Where(item => item.UserId is null && Text(item.Payload["type"]) == "admission_reporting")
            .Select(item =>
            {
                var output = RecordJson(item);
                output["schoolName"] = School(data, item.SchoolId)?.Name ?? "";
                output["examName"] = data.Operational.Exams.FirstOrDefault(exam => exam.Id == item.ExamId)?.Data["name"]?.GetValue<string>() ?? "";
                var plan = Records(data, "plan", item.ExamId).FirstOrDefault(plan => plan.SchoolId == item.SchoolId)
                           ?? EmptyPlan(item.ExamId, item.SchoolId);
                output["progress"] = PlanProgress(data, plan);
                return output;
            }).ToArray();
        var accounts = data.Directory.Users.Where(item => item.Role == "admission_school").Select(item =>
        {
            var output = SafeUser(item);
            output["active"] = item.Active;
            output["createdAt"] = item.CreatedAt;
            output["schoolName"] = School(data, item.SchoolId)?.Name ?? "";
            output["schoolCode"] = School(data, item.SchoolId)?.Code ?? "";
            return output;
        }).ToArray();
        return Success(new JsonObject
        {
            ["ok"] = true,
            ["settings"] = new JsonArray(settings),
            ["plans"] = new JsonArray(plans),
            ["preferences"] = new JsonArray(preferences),
            ["preferenceRows"] = new JsonArray(PreferenceSnapshotRows(data)),
            ["placements"] = new JsonArray(placements),
            ["reportingRequests"] = new JsonArray(reporting),
            ["schoolAccounts"] = new JsonArray(accounts),
            ["schools"] = new JsonArray(data.Directory.Schools.Where(item => item.Active).Select(SchoolJson).ToArray()),
            ["admissionSchools"] = new JsonArray(data.Directory.Schools.Where(item => item.Active && item.IsAdmissionSchool).Select(SchoolJson).ToArray()),
            ["sourceSchools"] = new JsonArray(data.Directory.Schools.Where(item => item.Active && item.IsSourceSchool).Select(SchoolJson).ToArray()),
            ["exams"] = new JsonArray(data.Operational.Exams.Where(item => item.Data["archivedAt"] is null).Select(item => item.Data.DeepClone()).ToArray())
        });
    }

    public async Task<AdminEndpointResult> GetQualificationsAsync(string sessionToken, CancellationToken cancellationToken)
    {
        var context = await ResolveSchoolAsync(sessionToken, cancellationToken);
        if (context.Error is not null) return context.Error;
        var data = await LoadAsync(cancellationToken);
        var school = School(data, context.User!.SchoolId);
        if (school is not { Active: true, IsSourceSchool: true })
            return Error(403, "当前学校未设置为生源学校");
        var exams = Records(data, "setting").Where(item => Boolean(item.Payload["enabled"])).Select(setting =>
        {
            var exam = data.Operational.Exams.FirstOrDefault(item => item.Id == setting.ExamId);
            if (exam is null) return null;
            var output = RecordJson(setting);
            output["exam"] = PublicExam(exam);
            output["qualificationStatus"] = QualificationStatus(data, setting.ExamId, school.Id);
            return output;
        }).Where(item => item is not null).Cast<JsonNode>().ToArray();
        return Success(new JsonObject
        {
            ["ok"] = true,
            ["school"] = SchoolJson(school),
            ["exams"] = new JsonArray(exams)
        });
    }

    public Task<AdminEndpointResult> SaveQualificationAsync(
        string sessionToken, string examId, string userId, JsonObject body, CancellationToken cancellationToken) =>
        SaveQualificationsCoreAsync(sessionToken, examId, [userId], body, false, cancellationToken);

    public async Task<AdminEndpointResult> SaveQualificationsAsync(
        string sessionToken, string examId, JsonObject body, CancellationToken cancellationToken)
    {
        var userIds = (body["userIds"] as JsonArray ?? [])
            .Select(Text).Where(item => item.Length > 0).Distinct(StringComparer.Ordinal).ToArray();
        if (userIds.Length == 0) return Error(400, "请至少选择一名考生");
        return await SaveQualificationsCoreAsync(sessionToken, examId, userIds, body, true, cancellationToken);
    }

    public async Task<AdminEndpointResult> CreateAccountAsync(
        string sessionToken, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以创建招生学校账号", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var data = await LoadAsync(cancellationToken);
        var school = data.Directory.Schools.FirstOrDefault(item =>
            item.Id == Clean(Text(body["schoolId"]), 64) && item.Active && item.IsAdmissionSchool);
        var username = Clean(Text(body["username"]), 80);
        var password = Text(body["password"]);
        if (school is null || username.Length == 0 || password.Length < 8)
            return Error(400, "请选择学校，并填写登录账号和至少 8 位密码");
        if (data.Directory.Users.Any(item => item.Username.Equals(username, StringComparison.OrdinalIgnoreCase)))
            return Error(409, "登录账号已存在");
        var now = NowIso();
        var account = new AdminUser(
            Uid("usr"), username, "admission_school", null, school.Id, null,
            Clean(Text(body["displayName"]), 80) is { Length: > 0 } name ? name : $"{school.Name}招生办",
            null, true, false, false, null, now);
        await repository.CreateAccountAsync(
            account, passwords.Hash(password),
            Audit(user, "创建招生学校账号", $"{school.Name} · {username}"), cancellationToken);
        return Created(new JsonObject { ["ok"] = true, ["account"] = SafeUser(account) });
    }

    public async Task<AdminEndpointResult> UpdateAccountAsync(
        string sessionToken, string accountId, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以维护招生学校账号", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var directory = await directoryLoader.LoadAsync(cancellationToken);
        var target = directory.Users.FirstOrDefault(item => item.Id == accountId && item.Role == "admission_school");
        if (target is null) return Error(404, "招生学校账号不存在");
        var active = body.ContainsKey("active") ? Boolean(body["active"]) : target.Active;
        var displayName = Clean(Text(body["displayName"]), 80);
        if (displayName.Length == 0) displayName = target.DisplayName;
        await repository.UpdateAccountAsync(
            target.Id, displayName, active, null,
            Audit(user, active ? "启用招生学校账号" : "停用招生学校账号", $"{displayName} · {target.Username}"),
            cancellationToken);
        if (!active) await authenticationState.DeleteUserSessionsAsync(target.Id);
        return Success(new JsonObject
        {
            ["ok"] = true,
            ["account"] = SafeUser(target with { Active = active, DisplayName = displayName })
        });
    }

    public async Task<AdminEndpointResult> ResetAccountPasswordAsync(
        string sessionToken, string accountId, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以重置招生学校账号密码", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var directory = await directoryLoader.LoadAsync(cancellationToken);
        var target = directory.Users.FirstOrDefault(item => item.Id == accountId && item.Role == "admission_school");
        if (target is null) return Error(404, "招生学校账号不存在");
        var temporaryPassword = $"Reset-{Base64Url(RandomNumberGenerator.GetBytes(7))}";
        await repository.UpdateAccountAsync(
            target.Id, target.DisplayName, true, passwords.Hash(temporaryPassword),
            Audit(user, "重置招生学校账号密码", $"{target.DisplayName} · {target.Username}"),
            cancellationToken);
        await authenticationState.DeleteUserSessionsAsync(target.Id);
        return Success(new JsonObject
        {
            ["ok"] = true,
            ["username"] = target.Username,
            ["temporaryPassword"] = temporaryPassword
        });
    }

    public async Task<AdminEndpointResult> SaveSettingAsync(
        string sessionToken, string examId, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以设置志愿填报", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var data = await LoadAsync(cancellationToken);
        var exam = data.Operational.Exams.FirstOrDefault(item => item.Id == examId && item.Data["archivedAt"] is null);
        if (exam is null) return Error(404, "考试不存在或已经归档");
        var now = NowIso();
        var existing = Records(data, "setting", examId).FirstOrDefault();
        var requested = Text(body["status"]);
        var manual = new HashSet<string>(["draft", "filling", "closed"], StringComparer.Ordinal);
        var status = existing is not null && !manual.Contains(existing.Status)
            ? existing.Status
            : manual.Contains(requested) ? requested : existing?.Status ?? "draft";
        var payload = existing?.Payload.DeepClone().AsObject() ?? new JsonObject();
        payload["enabled"] = body["enabled"] is JsonValue enabled && enabled.TryGetValue<bool>(out var enabledValue) && enabledValue;
        payload["preferenceStart"] = Clean(Text(body["preferenceStart"]), 35);
        payload["preferenceEnd"] = Clean(Text(body["preferenceEnd"]), 35);
        payload["maxChoices"] = Math.Clamp(Integer(body["maxChoices"], 5), 1, 20);
        payload["maxSubmissions"] = Math.Clamp(Integer(body["maxSubmissions"], 3), 1, 50);
        payload["round"] = Math.Max(1, Integer(body["round"], Integer(existing?.Payload["round"], 1)));
        payload["autoPublish"] = body["autoPublish"] is not JsonValue auto || !auto.TryGetValue<bool>(out var autoValue) || autoValue;
        payload["progress"] = Clean(Text(body["progress"]), 200) is { Length: > 0 } progress ? progress : "等待志愿填报开始";
        if (TryDate(Text(payload["preferenceStart"]), out var start) &&
            TryDate(Text(payload["preferenceEnd"]), out var end) && start >= end)
            return Error(400, "志愿填报结束时间必须晚于开始时间");
        var setting = new CandidateAdmissionRecord(
            existing?.Id ?? Uid("admission_setting"), "setting", examId, existing?.UserId ?? user.Id, null,
            status, payload, existing?.CreatedAt ?? now, now);
        await repository.SaveRecordsAsync(
            [setting], Audit(user, "设置志愿填报", $"{Text(exam.Data["name"])} · {status}"), cancellationToken);
        return Success(new JsonObject { ["ok"] = true, ["setting"] = RecordJson(setting) });
    }

    public async Task<AdminEndpointResult> SavePlanAsync(
        string sessionToken, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以代招生学校上传计划", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var data = await LoadAsync(cancellationToken);
        var exam = data.Operational.Exams.FirstOrDefault(item =>
            item.Id == Clean(Text(body["examId"]), 64) && item.Data["archivedAt"] is null);
        var school = data.Directory.Schools.FirstOrDefault(item =>
            item.Id == Clean(Text(body["schoolId"]), 64) && item.Active && item.IsAdmissionSchool);
        var categories = NormalizeCategories(body["categories"]);
        if (exam is null || school is null || categories.Count == 0)
            return Error(400, "请选择考试、招生学校并填写有效计划");
        var codes = categories.Select(item => Text(item["code"])).ToArray();
        if (codes.Distinct(StringComparer.Ordinal).Count() != codes.Length)
            return Error(400, "招生类别代码不能重复");
        if (categories.Any(item => !ValidSpecialty(
                Text(item["specialtyCategory"]),
                Text(item["specialtyType"]))))
            return Error(400, "特长生招生类别的大类与小类不对应");
        foreach (var category in categories)
        {
            var allocations = category["indicatorAllocations"] as JsonArray ?? [];
            var ids = allocations.Select(item => Text(item?["sourceSchoolId"])).ToArray();
            if (ids.Distinct(StringComparer.Ordinal).Count() != ids.Length)
                return Error(400, "同一招生类别不能重复分配同一生源校指标");
            if (allocations.Sum(item => Number(item?["quota"])) > Number(category["quota"]))
                return Error(400, "指标分配合计不能超过类别计划人数");
            if (ids.Any(id => !data.Directory.Schools.Any(item => item.Id == id && item.Active && item.IsSourceSchool)))
                return Error(400, "指标分配中包含无效的生源学校");
        }
        var existing = Records(data, "plan", exam.Id).FirstOrDefault(item => item.SchoolId == school.Id);
        if (Records(data, "placement", exam.Id).Any(item => item.SchoolId == school.Id && item.Status != "withdrawn"))
            return Error(409, "已经产生投档记录，不能再修改该校本轮招生计划");
        var now = NowIso();
        var payload = existing?.Payload.DeepClone().AsObject() ?? new JsonObject();
        payload["categories"] = new JsonArray(categories.Select(item => item.DeepClone()).ToArray());
        payload["note"] = Clean(Text(body["note"]), 500);
        payload["submittedBy"] = user.DisplayName;
        payload["reviewedBy"] = user.DisplayName;
        payload["reviewedAt"] = now;
        payload["reviewNote"] = "超级管理员代上传并审核通过";
        var plan = new CandidateAdmissionRecord(
            existing?.Id ?? Uid("plan"), "plan", exam.Id, user.Id, school.Id, "approved",
            payload, existing?.CreatedAt ?? now, now);
        await repository.SaveRecordsAsync(
            [plan], Audit(user, "代上传招生计划", $"{school.Name} · {Text(exam.Data["name"])}"), cancellationToken);
        return new(existing is null ? 201 : 200, new JsonObject { ["ok"] = true, ["plan"] = RecordJson(plan) });
    }

    public async Task<AdminEndpointResult> ReviewPlanAsync(
        string sessionToken, string planId, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以审核招生计划", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var admission = await admissionRepository.LoadAsync(cancellationToken);
        var plan = admission.Records.FirstOrDefault(item => item.Id == planId && item.Kind == "plan");
        if (plan is null) return Error(404, "招生计划不存在");
        var status = Text(body["status"]);
        if (status is not ("approved" or "rejected")) return Error(400, "审核状态无效");
        var now = NowIso();
        var payload = plan.Payload.DeepClone().AsObject();
        payload["reviewNote"] = Clean(Text(body["reviewNote"]), 500);
        payload["reviewedBy"] = user.DisplayName;
        payload["reviewedAt"] = now;
        plan = plan with { Status = status, UpdatedAt = now, Payload = payload };
        await repository.SaveRecordsAsync(
            [plan], Audit(user, status == "approved" ? "审核通过招生计划" : "退回招生计划", plan.Id), cancellationToken);
        return Success(new JsonObject { ["ok"] = true, ["plan"] = RecordJson(plan) });
    }

    public async Task<AdminEndpointResult> RunActionAsync(
        string sessionToken, string examId, string action, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以执行投档与录取操作", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var data = await LoadAsync(cancellationToken);
        var setting = Records(data, "setting", examId).FirstOrDefault();
        if (setting is null || !Boolean(setting.Payload["enabled"])) return Error(404, "该考试未开启志愿填报");
        if (action == "supplementary")
            return Error(409, "补录必须由招生学校提交报到情况和补录决定，再经超级管理员审批开启");
        if (action == "match")
        {
            if (setting.Status is not ("closed" or "supplementary"))
                return Error(409, "请先结束当前填报阶段再投档");
            var placements = BuildPlacements(data, setting);
            var payload = setting.Payload.DeepClone().AsObject();
            payload["progress"] = $"第 {Integer(payload["round"], 1)} 轮投档完成，{placements.Count} 人已发送招生学校审核";
            setting = setting with { Status = "school_review", UpdatedAt = NowIso(), Payload = payload };
            await repository.SaveRecordsAsync(
                [setting, .. placements],
                Audit(user, "执行分数优先志愿投档", $"{setting.ExamId} · {placements.Count} 人"),
                cancellationToken);
            return Success(new JsonObject
            {
                ["ok"] = true,
                ["setting"] = RecordJson(setting),
                ["placementCount"] = placements.Count
            });
        }
        if (action != "finalize") return Error(404, "录取操作不存在");
        if (setting.Status != "school_review")
            return Error(409, "只有招生学校审核阶段可以签发录取通知书并开启报到");
        var placementsForExam = Records(data, "placement", examId).ToArray();
        if (placementsForExam.Any(item => item.Status is "school_review" or "withdrawal_pending"))
            return Error(409, "仍有招生学校审核或退档申请未处理");
        var now = NowIso();
        var round = Integer(setting.Payload["round"], 1);
        var admitted = AssignNoticeNumbers(
            data,
            placementsForExam.Where(item => item.Status == "admitted")
                .Select(item =>
                {
                    var payload = item.Payload.DeepClone().AsObject();
                    payload["finalizedRound"] = round;
                    return item with { Status = "final", UpdatedAt = now, Payload = payload };
                }).ToArray());
        var notifications = admitted.Select(item => new CandidateAdmissionRecord(
            Uid("notification"), "notification", examId, item.UserId, item.SchoolId, "unread",
            new JsonObject
            {
                ["title"] = "录取结果通知",
                ["message"] = $"你已被{School(data, item.SchoolId)?.Name ?? "招生学校"}录取",
                ["placementId"] = item.Id
            }, now, now)).ToArray();
        var reporting = Records(data, "plan", examId).Where(item => item.Status == "approved").Select(plan =>
        {
            var existing = ReportingRecord(data, examId, plan.SchoolId, round);
            var rows = existing?.Payload["rows"]?.DeepClone().AsArray() ?? [];
            var ids = rows.Select(item => Text(item?["placementId"])).ToHashSet(StringComparer.Ordinal);
            foreach (var placement in admitted.Where(item => item.SchoolId == plan.SchoolId && !ids.Contains(item.Id)))
                rows.Add(new JsonObject { ["placementId"] = placement.Id, ["status"] = "pending", ["note"] = "", ["updatedAt"] = now, ["source"] = "system" });
            return new CandidateAdmissionRecord(
                existing?.Id ?? Uid("admission_reporting"), "notification", examId, null, plan.SchoolId,
                "draft", new JsonObject
                {
                    ["type"] = "admission_reporting",
                    ["round"] = round,
                    ["rows"] = rows,
                    ["openedAt"] = now,
                    ["openedBy"] = user.DisplayName
                }, existing?.CreatedAt ?? now, now);
        }).ToArray();
        var publicRows = PublicAdmissionRows(data, admitted, round);
        var publication = Records(data, "notification", examId).FirstOrDefault(item =>
            item.UserId is null && Text(item.Payload["type"]) == "admission_round_publication" &&
            Integer(item.Payload["round"], 1) == round);
        var publicationPayload = publication?.Payload.DeepClone().AsObject() ?? new JsonObject();
        publicationPayload["type"] = "admission_round_publication";
        publicationPayload["round"] = round;
        publicationPayload["publishedAt"] = now;
        publicationPayload["publishedBy"] = user.DisplayName;
        publicationPayload["rows"] = publicRows;
        publication = new CandidateAdmissionRecord(
            publication?.Id ?? Uid("admission_round_publication"), "notification", examId, null, null,
            "published", publicationPayload, publication?.CreatedAt ?? now, now);
        var settingPayload = setting.Payload.DeepClone().AsObject();
        settingPayload["roundPublishedAt"] = now;
        settingPayload["progress"] = $"第 {round} 轮录取结束，{admitted.Count} 名考生已签发通知书，录取名单已公示，招生学校正在登记报到";
        setting = setting with { Status = "reporting", UpdatedAt = now, Payload = settingPayload };
        await repository.SaveRecordsAsync(
            [setting, .. admitted, .. notifications, .. reporting, publication],
            Audit(user, "签发录取通知书并公示本轮录取名单", $"{examId} · 第 {round} 轮 · {admitted.Count} 人"),
            cancellationToken);
        return Success(new JsonObject
        {
            ["ok"] = true,
            ["admittedCount"] = admitted.Count,
            ["reportingSchoolCount"] = reporting.Length,
            ["publicationId"] = publication.Id
        });
    }

    public async Task<AdminEndpointResult> ReviewReportingAsync(
        string sessionToken, string recordId, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以审批学校报到与补录决定", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var data = await LoadAsync(cancellationToken);
        var record = Records(data, "notification").FirstOrDefault(item =>
            item.Id == recordId && item.UserId is null && Text(item.Payload["type"]) == "admission_reporting");
        if (record is null || record.Status != "pending_approval")
            return Error(404, "待审批的报到与补录决定不存在");
        var now = NowIso();
        var payload = record.Payload.DeepClone().AsObject();
        var approvalNote = Clean(Text(body["approvalNote"]), 500);
        if (!ExactlyTrue(body["approved"]))
        {
            payload["approvalNote"] = approvalNote;
            payload["rejectedAt"] = now;
            payload["rejectedBy"] = user.DisplayName;
            record = record with { Status = "rejected", UpdatedAt = now, Payload = payload };
            await repository.SaveRecordsAsync(
                [record], Audit(user, "退回报到与补录决定", $"{record.SchoolId} · 第 {Integer(payload["round"], 1)} 轮"), cancellationToken);
            return Success(new JsonObject { ["ok"] = true, ["record"] = RecordJson(record) });
        }
        var supplement = Text(payload["supplementDecision"]) == "supplement";
        var preferenceEnd = Clean(Text(body["preferenceEnd"]), 35);
        if (supplement && (!TryDate(preferenceEnd, out var end) || end <= DateTimeOffset.UtcNow))
            return Error(400, "批准补录时必须设置晚于当前时间的补录志愿截止时间");
        payload["approvalNote"] = approvalNote;
        payload["approvedAt"] = now;
        payload["approvedBy"] = user.DisplayName;
        payload["approvedPreferenceEnd"] = supplement ? preferenceEnd : "";
        record = record with { Status = "approved", UpdatedAt = now, Payload = payload };
        var reportPlan = Records(data, "plan", record.ExamId)
            .FirstOrDefault(item => item.SchoolId == record.SchoolId)
            ?? EmptyPlan(record.ExamId, record.SchoolId);
        var recordsWithApproval = data.Admission.Records
            .Select(item => item.Id == record.Id ? record : item).ToArray();
        var approvedData = data with
        {
            Admission = data.Admission with { Records = recordsWithApproval }
        };
        payload["statistics"] = PlanProgress(approvedData, reportPlan);
        record = record with { Payload = payload };
        var changed = new List<CandidateAdmissionRecord>();
        if (supplement)
        {
            var notReported = (payload["rows"] as JsonArray ?? [])
                .Where(item => Text(item?["status"]) == "not_reported")
                .Select(item => Text(item?["placementId"])).ToHashSet(StringComparer.Ordinal);
            foreach (var placement in Records(data, "placement", record.ExamId)
                         .Where(item => item.SchoolId == record.SchoolId && item.Status == "final" && notReported.Contains(item.Id)))
            {
                var placementPayload = placement.Payload.DeepClone().AsObject();
                placementPayload["forfeitedAt"] = now;
                placementPayload["forfeitedReason"] = "未按规定完成报到，学校补录申请已获批准";
                changed.Add(placement with { Status = "forfeited", UpdatedAt = now, Payload = placementPayload });
            }
        }
        var replacements = new Dictionary<string, CandidateAdmissionRecord>(StringComparer.Ordinal)
        {
            [record.Id] = record
        };
        foreach (var placement in changed) replacements[placement.Id] = placement;
        var nextData = data with
        {
            Admission = data.Admission with
            {
                Records = data.Admission.Records
                    .Select(item => replacements.GetValueOrDefault(item.Id) ?? item).ToArray()
            }
        };
        var setting = Records(nextData, "setting", record.ExamId).FirstOrDefault();
        var round = Integer(payload["round"], 1);
        var plans = Records(nextData, "plan", record.ExamId).Where(item => item.Status == "approved").ToArray();
        var currentRecords = plans.Select(plan =>
            ReportingRecord(nextData, record.ExamId, plan.SchoolId, round)).ToArray();
        var allApproved = currentRecords.Length > 0 && currentRecords.All(item => item?.Status == "approved");
        List<CandidateAdmissionRecord> records = [record, .. changed];
        var completed = false;
        if (allApproved && setting is not null)
        {
            var settingPayload = setting.Payload.DeepClone().AsObject();
            var supplementRecords = currentRecords
                .Where(item => Text(item?.Payload["supplementDecision"]) == "supplement").ToArray();
            if (supplementRecords.Length > 0)
            {
                var supplementEnd = supplementRecords
                    .Select(item => Text(item?.Payload["approvedPreferenceEnd"]))
                    .Where(value => value.Length > 0)
                    .OrderBy(value => value, StringComparer.Ordinal)
                    .LastOrDefault() ?? preferenceEnd;
                settingPayload["round"] = round + 1;
                settingPayload["preferenceStart"] = now;
                settingPayload["preferenceEnd"] = supplementEnd;
                settingPayload["progress"] = $"第 {round + 1} 轮补录志愿填报进行中，截止 {SupplementDeadline(supplementEnd)}";
                setting = setting with { Status = "supplementary", UpdatedAt = now, Payload = settingPayload };
            }
            else
            {
                settingPayload["completedAt"] = now;
                settingPayload["progress"] = "全部招生学校报到情况与补录决定已审批，录取工作完成";
                setting = setting with { Status = "completed", UpdatedAt = now, Payload = settingPayload };
                var existingCutoff = Records(nextData, "cutoff_publication", record.ExamId).FirstOrDefault();
                var cutoffPayload = existingCutoff?.Payload.DeepClone().AsObject() ?? new JsonObject();
                cutoffPayload["publishedAt"] = now;
                cutoffPayload["rows"] = AdmissionCutoffRows(nextData, record.ExamId);
                records.Add(new CandidateAdmissionRecord(
                    existingCutoff?.Id ?? Uid("cutoff_publication"),
                    "cutoff_publication",
                    record.ExamId,
                    existingCutoff?.UserId ?? user.Id,
                    null,
                    "published",
                    cutoffPayload,
                    existingCutoff?.CreatedAt ?? now,
                    now));
                completed = true;
            }
            records.Add(setting);
        }
        await repository.SaveRecordsAsync(
            records,
            Audit(user, supplement ? "批准补录申请并公开报到情况" : "批准不补录决定并公开报到情况", $"{record.SchoolId} · 第 {round} 轮"),
            cancellationToken);
        return Success(new JsonObject
        {
            ["ok"] = true,
            ["record"] = RecordJson(record),
            ["forfeitedCount"] = changed.Count,
            ["phase"] = JsonValue.Create(setting?.Status),
            ["completed"] = completed
        });
    }

    public async Task<AdminEndpointResult> ReviewWithdrawalAsync(
        string sessionToken, string placementId, JsonObject body, CancellationToken cancellationToken)
    {
        var context = await ResolveAsync(sessionToken, "只有超级管理员可以审核退档", cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        var admission = await admissionRepository.LoadAsync(cancellationToken);
        var placement = admission.Records.FirstOrDefault(item =>
            item.Id == placementId && item.Kind == "placement" && item.Status == "withdrawal_pending");
        if (placement is null) return Error(404, "待审核退档申请不存在");
        var payload = placement.Payload.DeepClone().AsObject();
        payload["withdrawalReviewNote"] = Clean(Text(body["reviewNote"]), 500);
        placement = placement with
        {
            Status = ExactlyTrue(body["approved"]) ? "withdrawn" : "admitted",
            UpdatedAt = NowIso(),
            Payload = payload
        };
        await repository.SaveRecordsAsync(
            [placement],
            Audit(user, placement.Status == "withdrawn" ? "批准退档" : "驳回退档", placement.Id),
            cancellationToken);
        return Success(new JsonObject { ["ok"] = true, ["placement"] = RecordJson(placement) });
    }

    private async Task<AdminEndpointResult> SaveQualificationsCoreAsync(
        string sessionToken, string examId, IReadOnlyList<string> userIds, JsonObject body, bool bulk,
        CancellationToken cancellationToken)
    {
        var context = await ResolveSchoolAsync(sessionToken, cancellationToken);
        if (context.Error is not null) return context.Error;
        var user = context.User!;
        if (body["eligible"] is not JsonValue value || !value.TryGetValue<bool>(out var eligible))
            return Error(400, bulk ? "请选择批量设置为有资格或无资格" : "请选择有或无指标分配资格");
        var data = await LoadAsync(cancellationToken);
        var setting = Records(data, "setting", examId).FirstOrDefault();
        if (setting is null || !Boolean(setting.Payload["enabled"])) return Error(404, "该考试未启用志愿填报");
        var profiles = userIds.Select(id => data.Operational.Profiles.FirstOrDefault(item =>
            item.UserId == id && item.SchoolId == user.SchoolId && Boolean(item.Data["profileCompleted"]))).ToArray();
        if (profiles.Any(item => item is null) || profiles.Any(profile =>
                !data.Directory.Users.Any(account => account.Id == profile!.UserId && account.Role == "candidate" && account.Active)))
            return Error(bulk ? 403 : 404, bulk ? "批量名单中包含不属于本校的有效考生" : "本校有效考生不存在");
        var now = NowIso();
        var qualifications = profiles.Select(profile =>
        {
            var existing = Records(data, "indicator_qualification", examId).FirstOrDefault(item => item.UserId == profile!.UserId);
            return new CandidateAdmissionRecord(
                existing?.Id ?? Uid("indicator_qualification"), "indicator_qualification", examId,
                profile!.UserId, user.SchoolId, "confirmed",
                new JsonObject
                {
                    ["eligible"] = eligible,
                    ["confirmedBy"] = user.DisplayName,
                    ["confirmedAt"] = now
                }, existing?.CreatedAt ?? now, now);
        }).ToList();
        var replaced = data.Admission.Records.Where(item => qualifications.All(entry => entry.Id != item.Id))
            .Concat(qualifications).ToArray();
        data = data with { Admission = new CandidateAdmissionSnapshot(replaced, data.Admission.Schools) };
        var status = QualificationStatus(data, examId, user.SchoolId!);
        var records = new List<CandidateAdmissionRecord>(qualifications);
        if (Boolean(status["complete"]))
        {
            var existing = Records(data, "qualification_publication", examId).FirstOrDefault(item => item.SchoolId == user.SchoolId);
            var payload = existing?.Payload.DeepClone().AsObject() ?? new JsonObject();
            payload["publishedAt"] = now;
            payload["rows"] = status["rows"]!.DeepClone();
            records.Add(new CandidateAdmissionRecord(
                existing?.Id ?? Uid("qualification_publication"), "qualification_publication", examId,
                user.Id, user.SchoolId, "published", payload, existing?.CreatedAt ?? now, now));
        }
        await repository.SaveRecordsAsync(
            records,
            Audit(user, bulk ? "批量确认指标分配资格" : "确认指标分配资格",
                $"{qualifications.Count} 人 · {(eligible ? "有资格" : "无资格")}"),
            cancellationToken);
        var response = new JsonObject
        {
            ["ok"] = true,
            ["qualificationStatus"] = status,
            ["published"] = Boolean(status["complete"])
        };
        if (bulk) response["count"] = qualifications.Count;
        else
        {
            response["qualification"] = RecordJson(qualifications[0]);
            response["message"] = Boolean(status["complete"])
                ? "资格已确认；本校全部考生确认完成，公示已自动发布"
                : "资格已确认";
        }
        return Success(response);
    }

    private async Task<AdmissionData> LoadAsync(CancellationToken cancellationToken) =>
        new(
            await admissionRepository.LoadAsync(cancellationToken),
            await operationalLoader.LoadAsync(cancellationToken),
            await directoryLoader.LoadAsync(cancellationToken),
            await resultLoader.LoadAsync(cancellationToken),
            await resultLoader.LoadSummariesAsync(cancellationToken));

    private static IEnumerable<CandidateAdmissionRecord> Records(AdmissionData data, string kind, string? examId = null) =>
        data.Admission.Records.Where(item => item.Kind == kind && (examId is null || item.ExamId == examId));

    private static JsonObject QualificationStatus(AdmissionData data, string examId, string schoolId)
    {
        var profiles = data.Operational.Profiles.Where(profile =>
            profile.SchoolId == schoolId && Boolean(profile.Data["profileCompleted"]) &&
            data.Directory.Users.Any(user => user.Id == profile.UserId && user.Role == "candidate" && user.Active));
        var byUser = Records(data, "indicator_qualification", examId)
            .Where(item => item.SchoolId == schoolId && item.Status == "confirmed")
            .ToDictionary(item => item.UserId ?? "", StringComparer.Ordinal);
        var rows = profiles.Select(profile =>
        {
            byUser.TryGetValue(profile.UserId, out var qualification);
            var account = data.Directory.Users.FirstOrDefault(item => item.Id == profile.UserId);
            var category = Text(profile.Data["specialtyCategory"]);
            var type = Text(profile.Data["specialtyType"]);
            return new JsonObject
            {
                ["userId"] = profile.UserId,
                ["registrationNumber"] = account?.CandidateNumber ?? "",
                ["name"] = Text(profile.Data["name"]) is { Length: > 0 } name ? name : account?.DisplayName ?? "",
                ["eligible"] = Boolean(qualification?.Payload["eligible"]),
                ["confirmed"] = qualification is not null,
                ["confirmedAt"] = qualification is null ? "" : Text(qualification.Payload["confirmedAt"]) is { Length: > 0 } at ? at : qualification.UpdatedAt,
                ["specialtyCategory"] = category,
                ["specialtyType"] = type,
                ["specialtyLabel"] = SpecialtyLabel(category, type)
            };
        }).OrderBy(item => Text(item["registrationNumber"]), StringComparer.Ordinal).ToArray();
        return new JsonObject
        {
            ["total"] = rows.Length,
            ["confirmed"] = rows.Count(item => Boolean(item["confirmed"])),
            ["complete"] = rows.Length > 0 && rows.All(item => Boolean(item["confirmed"])),
            ["rows"] = new JsonArray(rows)
        };
    }

    private static JsonObject PreferenceJson(AdmissionData data, CandidateAdmissionRecord item)
    {
        var output = RecordJson(item);
        var account = data.Directory.Users.FirstOrDefault(user => user.Id == item.UserId);
        var profile = data.Operational.Profiles.FirstOrDefault(profile => profile.UserId == item.UserId);
        output["candidate"] = new JsonObject
        {
            ["registrationNumber"] = account?.CandidateNumber ?? "",
            ["name"] = Text(profile?.Data["name"])
        };
        var choices = item.Payload["choices"] as JsonArray ?? [];
        output["choices"] = new JsonArray(choices.Select(choice =>
        {
            var result = choice?.DeepClone().AsObject() ?? new JsonObject();
            var schoolId = Text(result["schoolId"]);
            var code = Text(result["categoryCode"]);
            var school = School(data, schoolId);
            var category = Records(data, "plan", item.ExamId).Where(plan => plan.SchoolId == schoolId)
                .SelectMany(PlanCategories).FirstOrDefault(entry => Text(entry["code"]) == code);
            result["schoolCode"] = Text(result["schoolCode"]) is { Length: > 0 } schoolCode ? schoolCode : school?.Code ?? "";
            result["schoolName"] = Text(result["schoolName"]) is { Length: > 0 } schoolName ? schoolName : school?.Name ?? "";
            result["categoryName"] = Text(result["categoryName"]) is { Length: > 0 } categoryName ? categoryName : Text(category?["name"]);
            return (JsonNode)result;
        }).ToArray());
        return output;
    }

    private static JsonObject PlacementJson(AdmissionData data, CandidateAdmissionRecord item)
    {
        var output = RecordJson(item);
        var account = data.Directory.Users.FirstOrDefault(user => user.Id == item.UserId);
        var profile = data.Operational.Profiles.FirstOrDefault(profile => profile.UserId == item.UserId);
        var school = School(data, item.SchoolId);
        var schoolClass = data.Directory.Classes.FirstOrDefault(entry => entry.Id == profile?.ClassId);
        output["candidate"] = new JsonObject
        {
            ["registrationNumber"] = account?.CandidateNumber ?? "",
            ["name"] = Text(profile?.Data["name"]),
            ["idNumberMasked"] = MaskId(Text(profile?.Data["idNumber"])),
            ["specialtyLabel"] = SpecialtyLabel(Text(profile?.Data["specialtyCategory"]), Text(profile?.Data["specialtyType"]))
        };
        output["sourceSchoolId"] = School(data, profile?.SchoolId)?.Id ?? "";
        output["sourceSchoolCode"] = School(data, profile?.SchoolId)?.Code ?? "";
        output["sourceSchoolName"] = School(data, profile?.SchoolId)?.Name ?? Text(profile?.Data["school"]);
        output["className"] = schoolClass?.Name ?? Text(profile?.Data["grade"]);
        output["schoolCode"] = school?.Code ?? "";
        output["schoolName"] = school?.Name ?? "";
        output["examCode"] = Text(data.Operational.Exams.FirstOrDefault(exam => exam.Id == item.ExamId)?.Data["code"]);
        output["examName"] = Text(data.Operational.Exams.FirstOrDefault(exam => exam.Id == item.ExamId)?.Data["name"]);
        output["admissionStatusLabel"] = item.Status switch
        {
            "school_review" => "学校审核中",
            "admitted" => "拟录取",
            "final" => "正式录取",
            "withdrawal_pending" => "退档待审",
            "withdrawn" => "已退档",
            "forfeited" => "未报到放弃",
            _ => item.Status
        };
        var reportingStatus = ReportingStatusCode(data, item);
        output["reportingStatus"] = reportingStatus;
        output["reportingStatusLabel"] = reportingStatus switch
        {
            "reported" => "已报到",
            "not_reported" => "未报到",
            "pending" => "待确认",
            _ => "—"
        };
        return output;
    }

    private static JsonObject[] PreferenceSnapshotRows(AdmissionData data) =>
        Records(data, "setting").Where(setting => Boolean(setting.Payload["enabled"])).SelectMany(setting =>
        {
            var round = Integer(setting.Payload["round"], 1);
            var maxSubmissions = Integer(setting.Payload["maxSubmissions"], 3);
            return data.Operational.Registrations.Where(item => item.ExamId == setting.ExamId && item.Status == "approved")
                .Select(registration =>
            {
                var profile = data.Operational.Profiles.FirstOrDefault(item => item.UserId == registration.UserId);
                var account = data.Directory.Users.FirstOrDefault(item => item.Id == registration.UserId);
                if (profile is null || account is not { Active: true, Role: "candidate" }) return null;
                var preference = Records(data, "preference", setting.ExamId).FirstOrDefault(item =>
                    item.UserId == profile.UserId && Integer(item.Payload["round"], 1) == round);
                var qualification = Records(data, "indicator_qualification", setting.ExamId).FirstOrDefault(item => item.UserId == profile.UserId);
                var exam = data.Operational.Exams.First(item => item.Id == setting.ExamId);
                var school = School(data, profile.SchoolId);
                var schoolClass = data.Directory.Classes.FirstOrDefault(item => item.Id == profile.ClassId);
                var submissionCount = Integer(preference?.Payload["submissionCount"]);
                var blocking = setting.Status == "supplementary" && Records(data, "placement", setting.ExamId).Any(item =>
                    item.UserId == profile.UserId && item.Status is "school_review" or "admitted" or "final" or "withdrawal_pending" or "forfeited");
                var status = blocking ? "ineligible"
                    : preference is not null && submissionCount >= maxSubmissions ? "locked"
                    : preference is not null ? "submitted"
                    : CandidateTotalScore(data, setting.ExamId, profile.UserId) is null ? "unavailable" : "unfilled";
                var fillStatus = status switch
                {
                    "submitted" => "已填报",
                    "locked" => "已锁定",
                    "unavailable" => "成绩未齐",
                    "ineligible" => "不可补录",
                    _ => "尚未填报"
                };
                var choices = preference is null
                    ? new JsonArray()
                    : PreferenceJson(data, preference)["choices"]!.DeepClone().AsArray();
                return new JsonObject
                {
                    ["id"] = $"{setting.ExamId}:{round}:{registration.UserId}",
                    ["examId"] = setting.ExamId,
                    ["examCode"] = Text(exam.Data["code"]),
                    ["examName"] = Text(exam.Data["name"]),
                    ["round"] = round,
                    ["phase"] = setting.Status,
                    ["status"] = status,
                    ["fillStatus"] = fillStatus,
                    ["lockStatus"] = status == "locked" ? "已锁定" : status == "ineligible" ? "不可填报" : "未锁定",
                    ["submissionCount"] = submissionCount,
                    ["maxSubmissions"] = maxSubmissions,
                    ["submittedAt"] = Text(preference?.Payload["submittedAt"]) is { Length: > 0 } submitted ? submitted : preference?.UpdatedAt ?? "",
                    ["sourceSchoolId"] = school?.Id ?? "",
                    ["sourceSchoolCode"] = school?.Code ?? "",
                    ["sourceSchoolName"] = school?.Name ?? Text(profile.Data["school"]),
                    ["className"] = schoolClass?.Name ?? Text(profile.Data["grade"]),
                    ["specialty"] = SpecialtyLabel(Text(profile.Data["specialtyCategory"]), Text(profile.Data["specialtyType"])),
                    ["indicatorStatus"] = qualification is null ? "未确认" : Boolean(qualification.Payload["eligible"]) ? "有资格" : "无资格",
                    ["candidate"] = new JsonObject
                    {
                        ["userId"] = registration.UserId,
                        ["registrationNumber"] = account.CandidateNumber ?? "",
                        ["name"] = Text(profile.Data["name"]) is { Length: > 0 } candidateName ? candidateName : account.DisplayName
                    },
                    ["choices"] = choices
                };
            });
        }).Where(item => item is not null).Cast<JsonObject>()
            .OrderBy(item => Text(item["examName"]), StringComparer.Create(CultureInfo.GetCultureInfo("zh-CN"), false))
            .ThenBy(item => Text(item["candidate"]?["registrationNumber"]), StringComparer.Ordinal).ToArray();

    private static List<CandidateAdmissionRecord> BuildPlacements(AdmissionData data, CandidateAdmissionRecord setting)
    {
        var round = Integer(setting.Payload["round"], 1);
        HashSet<string>? supplementarySchools = null;
        if (setting.Status == "supplementary")
        {
            supplementarySchools = Records(data, "notification", setting.ExamId)
                .Where(item => item.UserId is null &&
                               item.Status == "approved" &&
                               Text(item.Payload["type"]) == "admission_reporting" &&
                               Integer(item.Payload["round"], 1) == Math.Max(1, round - 1) &&
                               Text(item.Payload["supplementDecision"]) == "supplement")
                .Select(item => item.SchoolId)
                .OfType<string>()
                .ToHashSet(StringComparer.Ordinal);
            if (supplementarySchools.Count == 0) supplementarySchools = null;
        }
        var plans = Records(data, "plan", setting.ExamId)
            .Where(item => item.Status == "approved" &&
                           (supplementarySchools is null || supplementarySchools.Contains(item.SchoolId ?? "")))
            .ToArray();
        var categories = plans.SelectMany(plan => PlanCategories(plan).Select(category => (Plan: plan, Category: category)))
            .ToDictionary(item => $"{item.Plan.SchoolId}|{Text(item.Category["code"])}", StringComparer.Ordinal);
        var existing = Records(data, "placement", setting.ExamId).ToArray();
        var occupied = existing.Where(item => item.Status is not ("withdrawn" or "forfeited"))
            .GroupBy(item => $"{item.SchoolId}|{Text(item.Payload["categoryCode"])}|{Text(item.Payload["quotaBucket"])}")
            .ToDictionary(group => group.Key, group => group.Count(), StringComparer.Ordinal);
        var candidates = new List<AdmissionCandidate>();
        foreach (var preference in Records(data, "preference", setting.ExamId)
                     .Where(item => item.Status == "submitted" && Integer(item.Payload["round"], 1) == round))
        {
            if (existing.Any(item => item.UserId == preference.UserId && item.Status is "school_review" or "admitted" or "final" or "withdrawal_pending" or "forfeited"))
                continue;
            var score = CandidateTotalScore(data, setting.ExamId, preference.UserId);
            if (score is null) continue;
            var profile = data.Operational.Profiles.FirstOrDefault(item => item.UserId == preference.UserId);
            var registration = data.Operational.Registrations.FirstOrDefault(item =>
                item.UserId == preference.UserId && item.ExamId == setting.ExamId && item.Status == "approved");
            if (profile is null || registration is null) continue;
            candidates.Add(new(
                preference, profile, registration, score.Value, Number(registration.Data["featureScore"]), 0));
        }
        string NumberOf(AdmissionCandidate candidate) =>
            data.Directory.Users.FirstOrDefault(item => item.Id == candidate.Preference.UserId)?.CandidateNumber ?? "";
        var queue = new Queue<AdmissionCandidate>(
            candidates.OrderByDescending(item => item.CulturalScore).ThenBy(NumberOf, StringComparer.Ordinal));
        var accepted = new Dictionary<string, List<Proposal>>(StringComparer.Ordinal);
        while (queue.Count > 0)
        {
            var candidate = queue.Dequeue();
            var choices = candidate.Preference.Payload["choices"] as JsonArray ?? [];
            while (candidate.NextChoiceIndex < choices.Count)
            {
                var index = candidate.NextChoiceIndex;
                var choice = choices[candidate.NextChoiceIndex++];
                if (!categories.TryGetValue($"{Text(choice?["schoolId"])}|{Text(choice?["categoryCode"])}", out var target))
                    continue;
                var usesFeature = Text(target.Category["specialtyCategory"]).Length > 0 || Text(target.Category["specialtyType"]).Length > 0;
                if (!CandidateEligibleForCategory(candidate.Profile.Data, target.Category))
                    continue;
                var bucket = "general";
                var capacity = Number(target.Category["quota"]) - (target.Category["indicatorAllocations"] as JsonArray ?? []).Sum(item => Number(item?["quota"]));
                if (Text(choice?["preferenceType"]) == "indicator")
                {
                    var qualification = Records(data, "indicator_qualification", setting.ExamId).FirstOrDefault(item => item.UserId == candidate.Preference.UserId);
                    var allocation = (target.Category["indicatorAllocations"] as JsonArray ?? [])
                        .FirstOrDefault(item => Text(item?["sourceSchoolId"]) == candidate.Profile.SchoolId);
                    if (!Boolean(qualification?.Payload["eligible"]) || allocation is null) continue;
                    bucket = $"indicator:{candidate.Profile.SchoolId}";
                    capacity = Number(allocation["quota"]);
                }
                var bucketKey = $"{target.Plan.SchoolId}|{Text(target.Category["code"])}|{bucket}";
                var available = Math.Max(0, (int)capacity - occupied.GetValueOrDefault(bucketKey));
                if (available == 0) continue;
                var proposal = new Proposal(
                    candidate, target.Plan, target.Category, index + 1, bucket,
                    candidate.CulturalScore, candidate.FeatureScore,
                    Math.Round(candidate.CulturalScore + (usesFeature ? candidate.FeatureScore : 0), 2, MidpointRounding.AwayFromZero),
                    available);
                var bucketRows = accepted.GetValueOrDefault(bucketKey) ?? [];
                bucketRows.Add(proposal);
                bucketRows.Sort((left, right) =>
                {
                    var scoreOrder = right.TotalScore.CompareTo(left.TotalScore);
                    return scoreOrder != 0
                        ? scoreOrder
                        : StringComparer.Ordinal.Compare(NumberOf(left.Candidate), NumberOf(right.Candidate));
                });
                Proposal? rejected = null;
                if (bucketRows.Count > available)
                {
                    rejected = bucketRows[^1];
                    bucketRows.RemoveAt(bucketRows.Count - 1);
                }
                accepted[bucketKey] = bucketRows;
                if (rejected == proposal) continue;
                if (rejected is not null) queue.Enqueue(rejected.Candidate);
                break;
            }
        }
        var selected = accepted.Values.SelectMany(item => item)
            .OrderByDescending(item => item.TotalScore)
            .ThenBy(item => NumberOf(item.Candidate), StringComparer.Ordinal).ToArray();
        var now = NowIso();
        return selected.Select(item => new CandidateAdmissionRecord(
            Uid("placement"), "placement", setting.ExamId, item.Candidate.Preference.UserId, item.Plan.SchoolId,
            "school_review", new JsonObject
            {
                ["round"] = round,
                ["categoryCode"] = Text(item.Category["code"]),
                ["categoryName"] = Text(item.Category["name"]),
                ["preferenceOrder"] = item.PreferenceOrder,
                ["culturalScore"] = item.CulturalScore,
                ["totalScore"] = item.TotalScore,
                ["featureScore"] = item.FeatureScore,
                ["specialtyQualification"] = new JsonObject
                {
                    ["category"] = ResolveSpecialty(item.Candidate.Profile.Data).Category,
                    ["type"] = ResolveSpecialty(item.Candidate.Profile.Data).Type
                },
                ["quotaBucket"] = item.Bucket,
                ["schoolDecisionNote"] = "",
                ["withdrawalReason"] = "",
                ["withdrawalReviewNote"] = ""
            }, now, now)).ToList();
    }

    private static double? CandidateTotalScore(AdmissionData data, string examId, string? userId)
    {
        var registration = data.Operational.Registrations.FirstOrDefault(item =>
            item.ExamId == examId && item.UserId == userId && item.Status == "approved");
        if (registration is null) return null;
        var summary = data.ResultSummaries.FirstOrDefault(item => item.RegistrationId == registration.Id);
        return summary is { Complete: true } ? summary.TotalScore : null;
    }

    private static List<CandidateAdmissionRecord> AssignNoticeNumbers(AdmissionData data, IReadOnlyList<CandidateAdmissionRecord> placements)
    {
        var counters = Records(data, "placement").Where(item => Number(item.Payload["noticeSerial"]) > 0)
            .GroupBy(item => $"{item.SchoolId}\0{item.ExamId}")
            .ToDictionary(group => group.Key, group => (int)group.Max(item => Number(item.Payload["noticeSerial"])), StringComparer.Ordinal);
        var output = new List<CandidateAdmissionRecord>();
        foreach (var group in placements.GroupBy(item => $"{item.SchoolId}\0{item.ExamId}"))
        {
            var serial = counters.GetValueOrDefault(group.Key);
            foreach (var placement in group.OrderBy(item =>
                         data.Directory.Users.FirstOrDefault(user => user.Id == item.UserId)?.CandidateNumber, StringComparer.Ordinal))
            {
                if (Text(placement.Payload["noticeNumber"]).Length > 0) { output.Add(placement); continue; }
                serial++;
                var payload = placement.Payload.DeepClone().AsObject();
                payload["noticeSerial"] = serial;
                payload["noticeNumber"] = $"{CodePart(School(data, placement.SchoolId)?.Code, "SCHOOL")}-{CodePart(Text(data.Operational.Exams.FirstOrDefault(exam => exam.Id == placement.ExamId)?.Data["code"]), "EXAM")}-{serial:000000}";
                output.Add(placement with { Payload = payload });
            }
        }
        return output;
    }

    private static JsonArray PublicAdmissionRows(AdmissionData data, IReadOnlyList<CandidateAdmissionRecord> admitted, int round) =>
        new(admitted.Where(item => Integer(item.Payload["finalizedRound"], 1) == round).Select(item =>
        {
            var account = data.Directory.Users.FirstOrDefault(user => user.Id == item.UserId);
            var profile = data.Operational.Profiles.FirstOrDefault(profile => profile.UserId == item.UserId);
            return (JsonNode)new JsonObject
            {
                ["registrationNumber"] = account?.CandidateNumber ?? "",
                ["name"] = Text(profile?.Data["name"]),
                ["totalScore"] = Number(item.Payload["totalScore"]),
                ["admittedSchool"] = School(data, item.SchoolId)?.Name ?? "",
                ["categoryName"] = Text(item.Payload["categoryName"]),
                ["idNumberMasked"] = PublicMaskId(Text(profile?.Data["idNumber"])),
                ["phoneMasked"] = MaskPhone(Text(profile?.Data["phone"]))
            };
        }).OrderByDescending(item => Number(item["totalScore"]))
            .ThenBy(item => Text(item["registrationNumber"]), StringComparer.Ordinal).ToArray());

    private static JsonArray AdmissionCutoffRows(AdmissionData data, string examId)
    {
        var rows = Records(data, "placement", examId)
            .Where(item => item.Status == "final")
            .GroupBy(item => $"{item.SchoolId}|{Text(item.Payload["categoryCode"])}", StringComparer.Ordinal)
            .Select(group =>
            {
                var first = group.First();
                var scores = group.Select(item => Number(item.Payload["totalScore"])).ToArray();
                var plan = Records(data, "plan", examId).FirstOrDefault(item =>
                    item.Status == "approved" && item.SchoolId == first.SchoolId);
                var category = plan is null
                    ? null
                    : PlanCategories(plan).FirstOrDefault(item =>
                        Text(item["code"]) == Text(first.Payload["categoryCode"]));
                return (JsonNode)new JsonObject
                {
                    ["schoolId"] = JsonValue.Create(first.SchoolId),
                    ["schoolName"] = School(data, first.SchoolId)?.Name ?? "",
                    ["categoryCode"] = Text(first.Payload["categoryCode"]),
                    ["categoryName"] = Text(first.Payload["categoryName"]),
                    ["admittedCount"] = scores.Length,
                    ["planQuota"] = Number(category?["quota"]),
                    ["highestScore"] = scores.Max(),
                    ["cutoffScore"] = scores.Min()
                };
            })
            .OrderBy(item => Text(item?["schoolName"]),
                StringComparer.Create(CultureInfo.GetCultureInfo("zh-CN"), false))
            .ThenBy(item => Text(item?["categoryName"]),
                StringComparer.Create(CultureInfo.GetCultureInfo("zh-CN"), false))
            .ToArray();
        return new JsonArray(rows);
    }

    private static JsonObject PlanProgress(AdmissionData data, CandidateAdmissionRecord plan)
    {
        var quota = PlanCategories(plan).Sum(item => Number(item["quota"]));
        var placements = Records(data, "placement", plan.ExamId)
            .Where(item => item.SchoolId == plan.SchoolId && item.Status is not ("withdrawn" or "forfeited")).ToArray();
        var finals = placements.Where(item => item.Status == "final").ToArray();
        var reporting = Records(data, "notification", plan.ExamId)
            .Where(item => item.SchoolId == plan.SchoolId && item.UserId is null && Text(item.Payload["type"]) == "admission_reporting")
            .OrderByDescending(item => Integer(item.Payload["round"], 1)).ThenByDescending(item => item.UpdatedAt, StringComparer.Ordinal).ToArray();
        var rowMap = new Dictionary<string, JsonNode?>(StringComparer.Ordinal);
        foreach (var record in reporting.Reverse())
            foreach (var row in record.Payload["rows"] as JsonArray ?? []) rowMap[Text(row?["placementId"])] = row;
        var reported = finals.Count(item => Text(rowMap.GetValueOrDefault(item.Id)?["status"]) == "reported");
        var notReported = finals.Count(item => Text(rowMap.GetValueOrDefault(item.Id)?["status"]) == "not_reported");
        double Percent(int value) => quota == 0 ? 0 : Math.Round(value / quota * 100, 1, MidpointRounding.AwayFromZero);
        return new JsonObject
        {
            ["examId"] = plan.ExamId,
            ["schoolId"] = JsonValue.Create(plan.SchoolId),
            ["totalQuota"] = quota,
            ["placedCount"] = placements.Length,
            ["finalCount"] = finals.Length,
            ["reportedCount"] = reported,
            ["notReportedCount"] = notReported,
            ["pendingReportingCount"] = Math.Max(0, finals.Length - reported - notReported),
            ["admissionRate"] = Percent(finals.Length),
            ["reportingRate"] = Percent(reported),
            ["remainingQuota"] = Math.Max(0, quota - finals.Length),
            ["reportingGap"] = Math.Max(0, quota - reported),
            ["reportingStatus"] = reporting.FirstOrDefault()?.Status ?? "not_started",
            ["supplementDecision"] = Text(reporting.FirstOrDefault()?.Payload["supplementDecision"]),
            ["reportingUpdatedAt"] = JsonValue.Create(reporting.FirstOrDefault()?.UpdatedAt)
        };
    }

    private static JsonArray RemainingPlanQuota(AdmissionData data, CandidateAdmissionRecord plan) =>
        new(PlanCategories(plan).Select(category =>
        {
            var output = category.DeepClone().AsObject();
            var used = Records(data, "placement", plan.ExamId).Count(item =>
                item.SchoolId == plan.SchoolId && Text(item.Payload["categoryCode"]) == Text(category["code"]) &&
                item.Status is not ("withdrawn" or "forfeited"));
            output["used"] = used;
            output["remaining"] = Math.Max(0, Number(category["quota"]) - used);
            return (JsonNode)output;
        }).ToArray());

    private static CandidateAdmissionRecord? ReportingRecord(AdmissionData data, string examId, string? schoolId, int round) =>
        Records(data, "notification", examId).Where(item =>
                item.SchoolId == schoolId && item.UserId is null && Text(item.Payload["type"]) == "admission_reporting")
            .OrderByDescending(item => Integer(item.Payload["round"], 1)).ThenByDescending(item => item.UpdatedAt, StringComparer.Ordinal)
            .FirstOrDefault(item => Integer(item.Payload["round"], 1) == round);

    private static string ReportingStatusCode(AdmissionData data, CandidateAdmissionRecord placement)
    {
        foreach (var record in Records(data, "notification", placement.ExamId)
                     .Where(item => item.SchoolId == placement.SchoolId && Text(item.Payload["type"]) == "admission_reporting")
                     .OrderByDescending(item => Integer(item.Payload["round"], 1)))
        {
            var row = (record.Payload["rows"] as JsonArray ?? []).FirstOrDefault(item => Text(item?["placementId"]) == placement.Id);
            if (row is not null) return Text(row["status"]);
        }
        return placement.Status == "final" ? "pending" : "";
    }

    private async Task<ResolvedAdmin> ResolveAsync(string token, string forbidden, CancellationToken cancellationToken)
    {
        var context = await ResolveAnyAdminAsync(token, cancellationToken);
        if (context.Error is not null) return context;
        return context.User!.AdminLevel == "super" ? context : ResolvedAdmin.Failed(Error(403, forbidden));
    }

    private async Task<ResolvedAdmin> ResolveSchoolAsync(string token, CancellationToken cancellationToken)
    {
        var context = await ResolveAnyAdminAsync(token, cancellationToken);
        if (context.Error is not null) return context;
        return context.User!.AdminLevel == "school" && context.User.SchoolId is not null
            ? context
            : ResolvedAdmin.Failed(Error(403, "只有生源校学校管理员可以确认指标分配资格"));
    }

    private async Task<ResolvedAdmin> ResolveAnyAdminAsync(string token, CancellationToken cancellationToken)
    {
        if (token.Length == 0) return ResolvedAdmin.Failed(Error(401, "请先登录"));
        var userId = await authenticationState.GetSessionUserIdAsync(token);
        if (userId is null) return ResolvedAdmin.Failed(Error(401, "请先登录"));
        var user = await authenticationRepository.FindUserByIdAsync(userId, cancellationToken);
        if (user is not { Active: true, ArchivedAt: null }) return ResolvedAdmin.Failed(Error(401, "请先登录"));
        return user.Role == "admin" ? new(user, null) : ResolvedAdmin.Failed(Error(403, "当前账号无权执行此操作"));
    }

    private static IReadOnlyList<JsonObject> PlanCategories(CandidateAdmissionRecord plan) =>
        (plan.Payload["categories"] as JsonArray ?? []).OfType<JsonObject>().ToArray();

    private static List<JsonObject> NormalizeCategories(JsonNode? node) =>
        (node as JsonArray ?? []).OfType<JsonObject>().Select((item, index) =>
        {
            var allocations = (item["indicatorAllocations"] as JsonArray ?? []).OfType<JsonObject>()
                .Select(allocation => (JsonNode)new JsonObject
                {
                    ["sourceSchoolId"] = Clean(Text(allocation["sourceSchoolId"]), 64),
                    ["quota"] = Math.Max(0, Integer(allocation["quota"]))
                }).Where(allocation => Text(allocation?["sourceSchoolId"]).Length > 0 && Number(allocation?["quota"]) > 0).ToArray();
            return new JsonObject
            {
                ["code"] = Clean(Text(item["code"]), 40) is { Length: > 0 } code ? code : $"category-{index + 1}",
                ["name"] = Clean(Text(item["name"]), 80),
                ["quota"] = Math.Max(0, Integer(item["quota"])),
                ["specialtyCategory"] = Clean(Text(item["specialtyCategory"]), 30),
                ["specialtyType"] = Clean(Text(item["specialtyType"]), 30),
                ["indicatorAllocations"] = new JsonArray(allocations)
            };
        }).Where(item => Text(item["name"]).Length > 0 && Number(item["quota"]) > 0).ToList();

    private static JsonObject RecordJson(CandidateAdmissionRecord item) => new()
    {
        ["id"] = item.Id,
        ["kind"] = item.Kind,
        ["examId"] = item.ExamId,
        ["userId"] = JsonValue.Create(item.UserId),
        ["schoolId"] = JsonValue.Create(item.SchoolId),
        ["status"] = item.Status,
        ["payload"] = item.Payload.DeepClone(),
        ["createdAt"] = item.CreatedAt,
        ["updatedAt"] = item.UpdatedAt
    };

    private static JsonObject PublicExam(OperationalExam exam)
    {
        var output = exam.Data.DeepClone().AsObject();
        output["totalScore"] = exam.Subjects.Sum(item => Number(item["fullScore"]));
        var now = DateTimeOffset.UtcNow;
        output["registrationState"] = exam.Data["archivedAt"] is not null ? "archived"
            : TryDate(Text(exam.Data["registrationStart"]), out var start) && now < start ? "upcoming"
            : TryDate(Text(exam.Data["registrationEnd"]), out var end) && now > end ? "closed" : "open";
        return output;
    }

    private static AdminSchool? School(AdmissionData data, string? id) =>
        data.Directory.Schools.FirstOrDefault(item => item.Id == id);
    private static JsonObject SchoolJson(AdminSchool item) => new()
    {
        ["id"] = item.Id,
        ["name"] = item.Name,
        ["code"] = item.Code,
        ["address"] = item.Address,
        ["isSourceSchool"] = item.IsSourceSchool,
        ["isAdmissionSchool"] = item.IsAdmissionSchool,
        ["active"] = item.Active
    };
    private static JsonObject SafeUser(AdminUser item) => new()
    {
        ["id"] = item.Id,
        ["username"] = item.Username,
        ["role"] = item.Role,
        ["adminLevel"] = item.Role == "admin" ? item.AdminLevel ?? "super" : null,
        ["schoolId"] = JsonValue.Create(item.SchoolId),
        ["classId"] = JsonValue.Create(item.ClassId),
        ["displayName"] = item.DisplayName,
        ["candidateNumber"] = JsonValue.Create(item.CandidateNumber),
        ["mustChangePassword"] = item.MustChangePassword,
        ["totpEnabled"] = item.TotpEnabled,
        ["archived"] = item.ArchivedAt is not null
    };
    private static CandidateAdmissionRecord EmptyPlan(string examId, string? schoolId) =>
        new("", "plan", examId, null, schoolId, "", new JsonObject { ["categories"] = new JsonArray() }, "", "");
    private static string SpecialtyLabel(string category, string type)
    {
        var categoryName = category switch { "sports" => "体育", "arts" => "艺术", _ => "" };
        var typeName = type switch
        {
            "track_field" => "田径",
            "basketball" => "篮球",
            "football" => "足球",
            "volleyball" => "排球",
            "table_tennis" => "乒乓球",
            "badminton" => "羽毛球",
            "swimming" => "游泳",
            "martial_arts" => "武术",
            "aerobics_cheer" => "健美操与啦啦操",
            "vocal_music" => "声乐",
            "instrumental_music" => "器乐",
            "dance" => "舞蹈",
            "fine_arts" => "美术",
            "calligraphy" => "书法",
            "drama_broadcasting" => "戏剧与播音",
            _ => ""
        };
        return categoryName.Length > 0 && typeName.Length > 0 ? $"{categoryName}·{typeName}" : "普通生";
    }
    private static bool ValidSpecialty(string category, string type)
    {
        if (category.Length == 0 && type.Length == 0) return true;
        return SpecialtyTypes.TryGetValue(category, out var types) &&
               types.Contains(type, StringComparer.Ordinal);
    }
    private static bool CandidateEligibleForCategory(JsonObject profile, JsonObject category)
    {
        var requiredCategory = Text(category["specialtyCategory"]);
        var requiredType = Text(category["specialtyType"]);
        if (requiredCategory.Length == 0 && LegacySpecialties.TryGetValue(requiredType, out var legacy))
            (requiredCategory, requiredType) = legacy;
        if (requiredCategory.Length == 0) return true;
        var qualification = ResolveSpecialty(profile);
        return qualification.Category == requiredCategory &&
               (requiredType.Length == 0 || qualification.Type == requiredType);
    }
    private static (string Category, string Type) ResolveSpecialty(JsonObject profile)
    {
        var category = Text(profile["specialtyCategory"]);
        var type = Text(profile["specialtyType"]);
        if (ValidSpecialty(category, type) && category.Length > 0) return (category, type);
        foreach (var value in profile["specialtyTypes"] as JsonArray ?? [])
            if (LegacySpecialties.TryGetValue(Text(value), out var legacy)) return legacy;
        return ("", "");
    }
    private static string SupplementDeadline(string value) =>
        TryDate(value, out var parsed)
            ? parsed.ToLocalTime().ToString("yyyy/M/d HH:mm:ss", CultureInfo.GetCultureInfo("zh-CN"))
            : value;
    private static string MaskId(string value) => value.Length > 8 ? $"{value[..4]}********{value[^4..]}" : "";
    private static string PublicMaskId(string value) => value.Length > 5 ? $"{value[..3]}***********{value[^2..]}" : "";
    private static string MaskPhone(string value) => value.Length > 7 ? $"{value[..3]}****{value[^4..]}" : "";
    private static string CodePart(string? value, string fallback)
    {
        var chars = (value ?? "").Trim().ToUpperInvariant().Where(character =>
            character is >= 'A' and <= 'Z' or >= '0' and <= '9' or '-').ToArray();
        return chars.Length == 0 ? fallback : new string(chars);
    }
    private static string Base64Url(byte[] value) => Convert.ToBase64String(value).TrimEnd('=').Replace('+', '-').Replace('/', '_');
    private static bool ExactlyTrue(JsonNode? node) => node is JsonValue value && value.TryGetValue<bool>(out var boolean) && boolean;
    private static bool Boolean(JsonNode? node)
    {
        if (node is null) return false;
        if (node is JsonValue value && value.TryGetValue<bool>(out var boolean)) return boolean;
        if (node is JsonValue number && number.TryGetValue<double>(out var numeric)) return numeric != 0;
        return node.ToString().Length > 0;
    }
    private static int Integer(JsonNode? node, int fallback = 0) =>
        int.TryParse(Text(node), NumberStyles.Integer, CultureInfo.InvariantCulture, out var value) ? value : fallback;
    private static double Number(JsonNode? node) =>
        double.TryParse(Text(node), NumberStyles.Float, CultureInfo.InvariantCulture, out var value) ? value : 0;
    private static string Text(JsonNode? node) =>
        node is JsonValue value && value.TryGetValue<string>(out var text) ? text : node?.ToString() ?? "";
    private static string Clean(string value, int maximum)
    {
        var cleaned = value.Trim();
        return cleaned[..Math.Min(cleaned.Length, maximum)];
    }
    private static bool TryDate(string value, out DateTimeOffset parsed) =>
        DateTimeOffset.TryParse(value, CultureInfo.InvariantCulture, DateTimeStyles.AssumeUniversal, out parsed);
    private static string NowIso() => DateTimeOffset.UtcNow.ToString("yyyy-MM-dd'T'HH:mm:ss.fff'Z'", CultureInfo.InvariantCulture);
    private static string Uid(string prefix) =>
        $"{prefix}_{ToBase36(DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())}_{Convert.ToHexStringLower(RandomNumberGenerator.GetBytes(4))}";
    private static string ToBase36(long value)
    {
        const string alphabet = "0123456789abcdefghijklmnopqrstuvwxyz";
        Span<char> buffer = stackalloc char[16];
        var position = buffer.Length;
        do { buffer[--position] = alphabet[(int)(value % 36)]; value /= 36; } while (value > 0);
        return new(buffer[position..]);
    }
    private static AdminAuditEntry Audit(AuthenticationUser user, string action, string detail) =>
        new(Uid("log"), user.Id, action, detail, NowIso());
    private static AdminEndpointResult Success(JsonObject body) => new(200, body);
    private static AdminEndpointResult Created(JsonObject body) => new(201, body);
    private static AdminEndpointResult Error(int status, string message) =>
        new(status, new JsonObject { ["ok"] = false, ["message"] = message });

    private sealed record AdmissionData(
        CandidateAdmissionSnapshot Admission,
        AdminOperationalSnapshot Operational,
        AdminAccountBatchSnapshot Directory,
        IReadOnlyList<AdminWorkflowResult> Results,
        IReadOnlyList<AdminRegistrationResultSummary> ResultSummaries);
    private sealed record ResolvedAdmin(AuthenticationUser? User, AdminEndpointResult? Error)
    {
        public static ResolvedAdmin Failed(AdminEndpointResult error) => new(null, error);
    }
    private sealed class AdmissionCandidate(
        CandidateAdmissionRecord preference,
        OperationalProfile profile,
        OperationalRegistration registration,
        double culturalScore,
        double featureScore,
        int nextChoiceIndex)
    {
        public CandidateAdmissionRecord Preference { get; } = preference;
        public OperationalProfile Profile { get; } = profile;
        public OperationalRegistration Registration { get; } = registration;
        public double CulturalScore { get; } = culturalScore;
        public double FeatureScore { get; } = featureScore;
        public int NextChoiceIndex { get; set; } = nextChoiceIndex;
    }
    private sealed record Proposal(
        AdmissionCandidate Candidate,
        CandidateAdmissionRecord Plan,
        JsonObject Category,
        int PreferenceOrder,
        string Bucket,
        double CulturalScore,
        double FeatureScore,
        double TotalScore,
        int Capacity);
}
