<?php

declare(strict_types=1);

require_once __DIR__ . '/prompt_variant.php';
require_once __DIR__ . '/prompt_variant_review.php';
require_once __DIR__ . '/variant_stem_observation_grammar.php';

/**
 * Variant-only repair model (mirrors main SBA 5.1 review model name; does not change shared config).
 */
function variantOpenAiRepairModel(): string
{
    return variantOpenAiReviewModel();
}

/**
 * @return list<string>
 */
function variantRepairQuestionContentFields(): array
{
    return [
        'title',
        'stem',
        'lead_in',
        'option_a',
        'option_b',
        'option_c',
        'option_d',
        'option_e',
        'correct_answer_letter',
        'justification',
    ];
}

/**
 * @param array<string, mixed> $row
 * @return array<string, string>
 */
function variantQuestionRowToRepairSnapshot(array $row): array
{
    $out = [];
    foreach (variantRepairQuestionContentFields() as $field) {
        $out[$field] = trim((string) ($row[$field] ?? ''));
    }
    $letter = strtoupper($out['correct_answer_letter']);
    $options = [
        'A' => $out['option_a'],
        'B' => $out['option_b'],
        'C' => $out['option_c'],
        'D' => $out['option_d'],
        'E' => $out['option_e'],
    ];
    $out['correct_answer'] = $options[$letter] ?? trim((string) ($row['correct_answer'] ?? ''));

    return $out;
}

/**
 * @param array<string, string> $before
 * @param array<string, string> $after
 * @return list<string>
 */
function variantBuildChangeLogFromDiff(array $before, array $after): array
{
    $labels = [
        'title' => 'Title',
        'stem' => 'Stem',
        'lead_in' => 'Lead-in',
        'option_a' => 'Option A',
        'option_b' => 'Option B',
        'option_c' => 'Option C',
        'option_d' => 'Option D',
        'option_e' => 'Option E',
        'correct_answer_letter' => 'Correct answer letter',
        'justification' => 'Justification',
    ];

    $log = [];
    foreach ($labels as $field => $label) {
        $b = $before[$field] ?? '';
        $a = $after[$field] ?? '';
        if ($b !== $a && $a !== '') {
            if (strlen($b) > 80 || strlen($a) > 80) {
                $log[] = 'Updated ' . $label . ' for MLA AKT style, clinical accuracy, or answer alignment.';
            } else {
                $log[] = 'Updated ' . $label . ': “' . $b . '” → “' . $a . '”.';
            }
        }
    }

    return $log;
}

/**
 * @param array<string, mixed> $sourceQuestion
 * @param array<string, mixed> $variant
 * @param array<string, mixed> $advisoryReview
 */
function buildVariantRepairPrompt(array $sourceQuestion, array $variant, array $advisoryReview): string
{
    $data = is_array($sourceQuestion['data'] ?? null) ? $sourceQuestion['data'] : [];
    $rowNumber = (string) ($sourceQuestion['row_number'] ?? '');

    $questionTitle = embedVariantField($data['Question title'] ?? '');
    $questionText = embedVariantField($data['Question text'] ?? '');
    $stemSeed = embedVariantField($data['Stem'] ?? '');
    $correctAnswer = embedVariantField($data['Correct answer'] ?? '');
    $correctAnswerLetter = embedVariantField($data['Correct answer letter'] ?? '');
    $justificationSeed = embedVariantField($data['Justification'] ?? $data['justification'] ?? '');
    $learningOutcome = embedVariantField(
        $data['Learning outcome'] ?? $data['Learning outcomes'] ?? $data['Learning Outcome'] ?? ''
    );

    $seedOptA = embedVariantField($data['Option A'] ?? '', 2000);
    $seedOptB = embedVariantField($data['Option B'] ?? '', 2000);
    $seedOptC = embedVariantField($data['Option C'] ?? '', 2000);
    $seedOptD = embedVariantField($data['Option D'] ?? '', 2000);
    $seedOptE = embedVariantField($data['Option E'] ?? '', 2000);

    $snapshot = variantQuestionRowToRepairSnapshot($variant);
    $variantJson = json_encode($snapshot, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    if ($variantJson === false) {
        $variantJson = '{}';
    }

    $reviewJson = json_encode($advisoryReview, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    if ($reviewJson === false) {
        $reviewJson = '{}';
    }

    $metaBlock = implode("\n", [
        variantPromptMetaLine('Learning outcome(s)', $learningOutcome),
        variantPromptMetaLine('Core condition', embedVariantField($data['Core condition'] ?? '')),
        variantPromptMetaLine('Skill', embedVariantField($data['Skill'] ?? '')),
    ]);

    return <<<PROMPT
You are an expert UK medical school SBA editor repairing a **generated variant** of an existing item for MLA AKT / MS AKT use.

**CRITICAL**
- Produce a **repaired draft** only. You do **not** approve the item for export.
- **Tutor review** and manual **Done** approval remain required.
- Repair only what is necessary; preserve educational equivalence and the source **correct answer concept**.
- Return **valid JSON only** (no markdown fences).

**MISSING METADATA**
- If learning outcomes or tags are absent, infer the intended learning point from source stem, options, correct answer and justification.
- Do **not** invent formal learning outcomes, curriculum codes, or tags.

**SOURCE ANSWER CONCEPT (anchor)**
- Source correct answer letter: {$correctAnswerLetter}
- Source correct answer text: {$correctAnswer}
- If the variant has drifted from this concept, **restore** the source answer concept (reword the keyed option if needed; you may change which letter is keyed only if required to fix a clear error while keeping the same clinical concept).

**PRESERVE THE FORMAL CORRECT ANSWER CONCEPT (exact where possible)**
- If the source correct answer is a **named** diagnosis, condition, organism, investigation, drug, or management action, the repaired **keyed option** must preserve that **named concept**.
- Do **not** replace a named diagnosis or condition with a **symptom** or **sign**.
- Symptoms and signs may appear in the **stem** to support the answer, but must **not** replace the formal answer concept in the keyed option.
- Examples: if the source answer is **“Laryngitis”**, the repaired correct answer must be **“Laryngitis”** or **“Acute laryngitis”**, **not** “Hoarseness of voice”, “Hoarse voice”, or similar symptom labels.
- Examples: prefer **“Arrange review after next menstruation”** over “Advise to monitor for changes and arrange review after her next period”.
- Do **not** replace a concise named answer with a vague descriptive phrase unless strictly necessary for clinical accuracy.
- If the variant keyed option has drifted to a symptom/sign or long description, **restore** the source formal label (or the closest MS AKT-style equivalent).

**GUIDELINE-DETERMINING DETAILS — DO NOT ALTER**
- Do **not** change **age**, sex, pregnancy status, ethnicity/family origin, comorbidities, renal function, medication history, timing, severity, or clinical **setting** if those details determine the correct answer or guideline pathway.
- Before changing any demographic or clinical detail, infer whether it is a **reasoning anchor** (part of what makes the source answer correct). If yes, **preserve** it.
- Only vary surface details that do **not** change the clinical decision, guideline pathway, or diagnostic logic.
- **Age thresholds:** if the source answer depends on an age threshold (e.g. hypertension first-line therapy), keep the patient on the **same side** of that threshold.
- Example: if **amlodipine** is correct because the patient is **aged 55 or over**, the repaired variant must keep age **55 or over** — do **not** reduce age to 54 or below unless the source did so and the answer still holds.
- Do **not** add comorbidities (e.g. asthma, diabetes, chronic kidney disease, pregnancy) unless present in the source or clinically necessary **without** altering which answer is best.

**REASONING ANCHORS VS SURFACE DETAILS**
- Treat age, sex, pregnancy, key comorbidities, renal function, current drugs, severity, timing, and setting as **reasoning anchors** when they support the source answer or UK guideline logic.
- Preserve reasoning anchors; change only incidental vignette colour (names, dates, minor symptoms) that does not affect the decision.

**CORRECT ANSWER AND JUSTIFICATION ALIGNMENT**
- The **justification** must explain the **same answer concept** as the keyed option (same diagnosis, drug, investigation, organism, or management step).
- Do **not** justify a **diagnosis** while keying a **symptom/sign**, or vice versa.
- Do **not** justify one guideline pathway while the stem uses patient details that imply a **different** pathway.
- If you restore a formal answer concept, update the justification to match.

**EDUCATIONAL EQUIVALENCE**
- Same learning point / reasoning as the source.
- Sufficiently **different** surface details from the source (not a superficial paraphrase).
- Not so different that it becomes an unrelated question.
- Exactly **one** clearly best answer; distractors plausible, homogeneous, clearly less correct.
- Stem must include enough evidence to support the keyed answer.

**ANSWER OPTIONS — CONCISE MS AKT STYLE**
- Options should usually be **short**, with **one main component** each.
- Avoid **combining two actions** in one option (e.g. “Give X and arrange Y”) unless the source answer does this or the clinical decision clearly requires a single combined action.
- Avoid **over-explaining** options; do not add qualifiers, timelines, or counselling detail beyond MS AKT norms.
- Keep options **homogeneous** in type and **similar length** where possible (do not make the keyed option longer or more detailed than distractors).
- Management options: prefer one concise action (e.g. “Refer for specialist review”) over bundled actions unless the source tests a bundle.

**OPTIONS MUST BE SUPPORTED BY THE STEM**
- Do **not** introduce distractors that are not **present**, **implied**, or **clinically relevant** to the stem vignette.
- Do **not** base an option on facts **not mentioned** in the stem (or clearly inferable from it).
- If an option refers to a clinical feature, that feature must appear in the stem or follow directly from it.
- Do **not** add distractors such as “mild postoperative anxiety” unless anxiety is in the stem and relevant to the task.
- Remove or replace unsupported distractors during repair.

**SINGLE BEST ANSWER FAIRNESS**
- Avoid wording that makes the correct answer **overlap** conceptually with a distractor.
- Avoid distractors that are **obviously irrelevant** or from a different category than the keyed option.
- The keyed option should be clearly best on the vignette alone; distractors should be plausible but **clearly less correct**, not absurd.

**PRECISE UK CLINICAL TERMINOLOGY**
- Use **“biochemical abnormality”** (not “serological abnormality”) when referring to potassium, sodium, calcium, urea, creatinine, etc.
- British spelling; UK clinical terminology; generic medicine names; BNF-style wording where relevant.

**DO NOT OVER-REPAIR**
- Repair **only** what is necessary to fix issues flagged in review or clear MS AKT / concept drift problems.
- Do **not** lengthen the item unless extra detail is needed to support the single best answer.
- Do **not** add unsupported clinical detail or make the item so polished it feels unnatural for an SBA.

**EDI / ETHNICITY AND SENSITIVE DETAILS**
- Do **not** add ethnicity, nationality, religion, sexuality, disability, gender reassignment, or other EDI-relevant details unless **clinically necessary** for the tested decision.
- If the **source** did not include ethnicity and the answer does not require it, **remove** ethnicity if the variant added it.
- If you must add such a detail for clinical accuracy, the **change_log** must state **why** it was necessary.
- Do not create new tagging or metadata obligations unless necessary.

**SAME-CLASS AND NEAR-EQUIVALENT DISTRACTORS**
- Do **not** include two options from the **same drug class** if this weakens the single best answer.
- Example: avoid both **amlodipine** and **nifedipine** in a straightforward first-line hypertension item unless the stem specifically tests choice within calcium-channel blockers.
- Avoid duplicate-class or near-equivalent options unless the stem clearly makes one best; replace one with a plausible alternative from a **different** class or category.

**LEAD-INS**
- Prefer **“What?”** for most lead-ins (e.g. “What is the most appropriate treatment?”).
- Use **“Which?”** only when the option set is explicitly limited or candidates could infer the options from the stem alone.
- Repair **“Which…”** to **“What…”** when “Which” is not justified.
- Do **not** name the diagnosis in the lead-in if the candidate should **infer** it from the stem (e.g. prefer “What is the most appropriate treatment?” not “…for his pericarditis?” when pericarditis is the inferred diagnosis).
- Avoid negative lead-ins (“least likely”, etc.).

**CLINICALLY PLAUSIBLE EXAMINATION WORDING**
- Do **not** describe findings that would not normally be directly observed in the clinical setting unless the stem explains **how** they were assessed.
- Example: avoid “tender larynx” or “examination shows an inflamed larynx” in routine pre-operative assessment.
- Prefer plausible patient-centred wording (e.g. “her throat is inflamed and her voice is hoarse”) rather than implausible direct examination claims.
- Avoid “On examination” as an opener; integrate findings naturally into the stem.

**OBSERVATION WORDING — GRAMMAR (CRITICAL — REJECT CLIPPED POSSESSIVE PHRASES)**
- Do **not** write clipped possessive observation grammar in the **stem**.
- **Never** output: “His pulse 72 bpm”, “Her pulse 80 bpm”, “His BP 120/75 mmHg”, “Her BP 135/85 mmHg”, “His blood pressure 120/75 mmHg”, “Her blood pressure 135/85 mmHg”, or “His pulse 72 bpm, BP 120/75 mmHg, respiratory rate 9 breaths per minute…” (possessive + vital + number **without** “is”/“are”).
- If the stem uses **possessive sentence style** (starts with or includes “His/Her/Their …”), use **full grammatical sentences** with “is”/“are”, for example:
  - “His pulse is 72 bpm, blood pressure is 120/75 mmHg, respiratory rate is 9 breaths per minute and oxygen saturation is 80% breathing air.”
- **Or** use a **complete list-style** observation phrase **without** His/Her/Their at the start of the vital list, for example:
  - “temperature 36.8°C, pulse 72 bpm, BP 120/75 mmHg, respiratory rate 9 breaths per minute and oxygen saturation is 80% breathing air.”
- Do **not** mix possessive sentence openings (“His pulse…”) with bare list vitals (“BP 120/75 mmHg” without “is”) in the same stem.
- When repairing observation blocks, prefer fixing grammar over leaving clipped wording.

**MLA AKT / MS AKT STYLE (enforce on repaired item)**
- Present tense, third person; age and gender at start where appropriate; no patient names.
- Presenting problem in the first sentence; concise stem (~30–100 words unless clinically necessary).
- Simple wording; “has” not “presents with” / “complains of”.
- Avoid “known to have”, “diagnosed with”, “with a history of”.
- **Observations (preferred order when a full set is given):** temperature → pulse → blood pressure → respiratory rate → oxygen saturation.
  - **List-style block** (no His/Her/Their leading the vital list): use bare list wording, e.g. “temperature 37.2°C, pulse 80 bpm, BP 120/80 mmHg, respiratory rate 16 breaths per minute and oxygen saturation is 98% breathing air”.
  - **Possessive sentence style** (His/Her/Their …): every vital needs “is”/“are”, e.g. “His pulse is 80 bpm, blood pressure is 120/80 mmHg, respiratory rate is 16 breaths per minute and oxygen saturation is 98% breathing air” — **not** “His pulse 80 bpm” or “His BP 120/80 mmHg”.
  1. temperature (with unit, e.g. 37.2°C)
  2. pulse — “pulse N bpm” in list style; “pulse is N bpm” in possessive sentence style; not “pulse rate”
  3. blood pressure — “BP 120/80 mmHg” in list style; “blood pressure is 120/80 mmHg” in possessive sentence style
  4. respiratory rate — “respiratory rate 16 breaths per minute” (list) or “respiratory rate is 16 breaths per minute” (possessive sentence); not “respiratory rate 16/min”
  5. **oxygen saturation is 98% breathing air** — not “on room air”
- Do not reorder observations differently from the list above.
- **Investigations and units:** use **g/L**, **fL**, **mmol/L**, **µmol/L**, and **× 10⁹/L** where relevant; avoid lower-case **l** in units (not g/l, fl); use reference ranges consistently when values are given; prefer **× 10⁹/L** over caret notation such as 10^9/L in output text.
- Actual investigation values with reference ranges where possible, not vague summaries.
- Five non-empty options; plausible, homogeneous, **concise**, sentence case; logical order where possible (see **ANSWER OPTIONS** and **OPTIONS MUST BE SUPPORTED BY THE STEM** above).
- Eponyms without possessive apostrophes (e.g. Down syndrome); inclusive language without unnecessary EDI detail.

**SAFETY**
- No unsupported clinical facts; no unsafe or ambiguous keyed answer.
- If you cannot repair safely, set **repair_blocked**: true and omit **repaired_question**.

**SOURCE (row {$rowNumber})**
{$metaBlock}
- Title: {$questionTitle}
- Question text: {$questionText}
- Stem field: {$stemSeed}
- Options: A: {$seedOptA} | B: {$seedOptB} | C: {$seedOptC} | D: {$seedOptD} | E: {$seedOptE}
- Source justification: {$justificationSeed}

**CURRENT VARIANT (first pass)**
{$variantJson}

**REVIEW FINDINGS**
{$reviewJson}

**CHANGE LOG (accuracy required)**
- Provide **change_log**: an array of concise, tutor-readable strings describing each **actual** change in **repaired_question**.
- **Only** claim a fix if the repaired text **implements** it. Do not claim observations were standardised unless the repaired stem uses the MS AKT order above with correct wording (pulse N bpm, respiratory rate N breaths per minute, oxygen saturation is N% breathing air, etc.).
- If you add EDI-relevant detail, the change_log must state why it was clinically necessary.
- Do not claim UK spelling, lead-in, or distractor fixes unless visible in the repaired fields.
- If you **change the keyed answer wording**, state **why** (e.g. “Restored formal answer concept ‘Laryngitis’ to match the source instead of ‘Hoarseness of voice’.”).
- If you **preserve or restore age** or other reasoning anchors, note this when relevant (e.g. “Kept age 58 so age-based hypertension guidance still supports amlodipine.”).
- If you **keep the same answer concept** but reword for style, say so clearly (e.g. “Kept acute laryngitis as the answer concept; shortened option wording only.”).
- If you remove or replace unsupported distractors, name what was removed and why (not supported by the stem).
- If no changes are needed, set **no_changes_needed**: true, **repair_blocked**: false, and return the variant unchanged in **repaired_question** with an empty **change_log**.

OUTPUT — JSON only:

{
  "repair_blocked": false,
  "repair_blocked_reasons": [],
  "no_changes_needed": false,
  "repaired_question": {
    "title": "",
    "stem": "",
    "lead_in": "",
    "option_a": "",
    "option_b": "",
    "option_c": "",
    "option_d": "",
    "option_e": "",
    "correct_answer_letter": "",
    "justification": ""
  },
  "change_log": []
}
PROMPT;
}

/**
 * @param array<string, mixed> $raw
 * @param array<string, string> $originalSnapshot
 * @return array{ok: bool, data: ?array<string, mixed>, error: string}
 */
function normalizeVariantRepairResponse(array $raw, array $originalSnapshot): array
{
    if (!empty($raw['repair_blocked'])) {
        $reasons = [];
        if (isset($raw['repair_blocked_reasons']) && is_array($raw['repair_blocked_reasons'])) {
            foreach ($raw['repair_blocked_reasons'] as $r) {
                $t = trim((string) $r);
                if ($t !== '') {
                    $reasons[] = $t;
                }
            }
        }

        return [
            'ok' => true,
            'data' => [
                'repair_blocked' => true,
                'repair_blocked_reasons' => $reasons,
                'no_changes_needed' => false,
                'repaired_question' => null,
                'change_log' => [],
            ],
            'error' => '',
        ];
    }

    if (!empty($raw['no_changes_needed'])) {
        return [
            'ok' => true,
            'data' => [
                'repair_blocked' => false,
                'repair_blocked_reasons' => [],
                'no_changes_needed' => true,
                'repaired_question' => $originalSnapshot,
                'change_log' => [],
            ],
            'error' => '',
        ];
    }

    $repaired = $raw['repaired_question'] ?? null;
    if (!is_array($repaired)) {
        return ['ok' => false, 'data' => null, 'error' => 'Repair JSON missing repaired_question.'];
    }

    $norm = [];
    foreach (variantRepairQuestionContentFields() as $field) {
        $norm[$field] = trim((string) ($repaired[$field] ?? ''));
    }

    $letter = strtoupper($norm['correct_answer_letter']);
    if (!in_array($letter, ['A', 'B', 'C', 'D', 'E'], true)) {
        return ['ok' => false, 'data' => null, 'error' => 'Invalid correct_answer_letter in repaired question.'];
    }

    foreach (['option_a', 'option_b', 'option_c', 'option_d', 'option_e'] as $opt) {
        if ($norm[$opt] === '') {
            return ['ok' => false, 'data' => null, 'error' => 'Repaired question has an empty option.'];
        }
    }

    if ($norm['stem'] === '' || $norm['lead_in'] === '') {
        return ['ok' => false, 'data' => null, 'error' => 'Repaired question missing stem or lead-in.'];
    }

    $options = [
        'A' => $norm['option_a'],
        'B' => $norm['option_b'],
        'C' => $norm['option_c'],
        'D' => $norm['option_d'],
        'E' => $norm['option_e'],
    ];
    $norm['correct_answer_letter'] = $letter;
    $norm['correct_answer'] = $options[$letter];

    $changeLog = [];
    if (isset($raw['change_log']) && is_array($raw['change_log'])) {
        foreach ($raw['change_log'] as $entry) {
            $t = trim((string) $entry);
            if ($t !== '') {
                $changeLog[] = $t;
            }
        }
    }

    $stemNorm = variantNormalizeStemObservationGrammar($norm['stem']);
    $norm['stem'] = $stemNorm['stem'];
    if ($stemNorm['changed'] && !in_array('Standardised observation wording grammar in the stem.', $changeLog, true)) {
        $changeLog[] = 'Standardised observation wording grammar in the stem.';
    }

    $before = $originalSnapshot;
    $after = $norm;
    $unchanged = true;
    foreach (variantRepairQuestionContentFields() as $field) {
        if (($before[$field] ?? '') !== ($after[$field] ?? '')) {
            $unchanged = false;
            break;
        }
    }

    if ($unchanged) {
        return [
            'ok' => true,
            'data' => [
                'repair_blocked' => false,
                'repair_blocked_reasons' => [],
                'no_changes_needed' => true,
                'repaired_question' => $before,
                'change_log' => [],
            ],
            'error' => '',
        ];
    }

    if ($changeLog === []) {
        $changeLog = variantBuildChangeLogFromDiff($before, $after);
    }

    return [
        'ok' => true,
        'data' => [
            'repair_blocked' => false,
            'repair_blocked_reasons' => [],
            'no_changes_needed' => false,
            'repaired_question' => $after,
            'change_log' => $changeLog,
        ],
        'error' => '',
    ];
}

/**
 * @param array<string, string> $content
 * @return array<string, mixed>
 */
function variantRepairContentToApiQuestion(array $content, array $dbRow): array
{
    return [
        'id' => $dbRow['id'] ?? null,
        'title' => $content['title'],
        'stem' => $content['stem'],
        'lead_in' => $content['lead_in'],
        'option_a' => $content['option_a'],
        'option_b' => $content['option_b'],
        'option_c' => $content['option_c'],
        'option_d' => $content['option_d'],
        'option_e' => $content['option_e'],
        'correct_answer_letter' => $content['correct_answer_letter'],
        'correct_answer' => $content['correct_answer'],
        'justification' => $content['justification'],
        'specialty' => $dbRow['specialty'] ?? '',
        'condition_name' => $dbRow['condition_name'] ?? '',
        'presentation' => $dbRow['presentation'] ?? '',
        'skill' => $dbRow['skill'] ?? '',
        'summative_formative' => $dbRow['summative_formative'] ?? '',
        'year_level' => $dbRow['year_level'] ?? '',
        'tutor_comments' => $dbRow['tutor_comments'] ?? '',
        'status' => 'Draft',
        'source_type' => $dbRow['source_type'] ?? 'variant',
        'source_question_id' => $dbRow['source_question_id'] ?? null,
        'variant_number' => $dbRow['variant_number'] ?? null,
    ];
}

/**
 * @param PDO $pdo
 * @param array<string, string> $content
 * @return array{ok: bool, error: string}
 */
function variantApplyRepairToDraftVariant(PDO $pdo, string $questionId, array $content): array
{
    $sql = "UPDATE questions SET
        title = :title,
        stem = :stem,
        lead_in = :lead_in,
        option_a = :option_a,
        option_b = :option_b,
        option_c = :option_c,
        option_d = :option_d,
        option_e = :option_e,
        correct_answer_letter = :correct_answer_letter,
        correct_answer = :correct_answer,
        justification = :justification
    WHERE id = :question_id
      AND source_type = 'variant'
      AND status = 'Draft'";

    $stmt = $pdo->prepare($sql);
    $stmt->execute([
        'title' => $content['title'],
        'stem' => $content['stem'],
        'lead_in' => $content['lead_in'],
        'option_a' => $content['option_a'],
        'option_b' => $content['option_b'],
        'option_c' => $content['option_c'],
        'option_d' => $content['option_d'],
        'option_e' => $content['option_e'],
        'correct_answer_letter' => $content['correct_answer_letter'],
        'correct_answer' => $content['correct_answer'],
        'justification' => $content['justification'],
        'question_id' => $questionId,
    ]);

    if ($stmt->rowCount() < 1) {
        return ['ok' => false, 'error' => 'Draft variant could not be updated (wrong type, status, or ID).'];
    }

    return ['ok' => true, 'error' => ''];
}
