<?php

/**
 * Read-only clinical safety review for main SBA generator questions (no auto-edits).
 */

/**
 * @param array<string, mixed> $question
 * @param list<array<string, mixed>> $styleWarnings
 * @param array<string, mixed> $reviewContext
 */
function buildSbaClinicalSafetyReviewerPrompt(
    array $question,
    array $styleWarnings = [],
    array $reviewContext = []
): string {
    $specialty = trim((string) ($question['specialty'] ?? ''));
    $condition = trim((string) ($question['condition_name'] ?? ''));
    $presentation = trim((string) ($question['presentation'] ?? ''));
    $yearLevel = trim((string) ($question['year_level'] ?? ''));
    $skill = trim((string) ($question['skill'] ?? ''));
    $tutorComments = trim((string) ($question['tutor_comments'] ?? ''));
    $title = trim((string) ($question['title'] ?? ''));
    $stem = trim((string) ($question['stem'] ?? ''));
    $leadIn = trim((string) ($question['lead_in'] ?? ''));
    $letter = trim((string) ($question['correct_answer_letter'] ?? ''));
    $correctAnswer = trim((string) ($question['correct_answer'] ?? ''));
    $justification = trim((string) ($question['justification'] ?? ''));

    $warningsJson = json_encode($styleWarnings, JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);
    if ($warningsJson === false) {
        $warningsJson = '[]';
    }

    $options = [
        'A' => trim((string) ($question['option_a'] ?? '')),
        'B' => trim((string) ($question['option_b'] ?? '')),
        'C' => trim((string) ($question['option_c'] ?? '')),
        'D' => trim((string) ($question['option_d'] ?? '')),
        'E' => trim((string) ($question['option_e'] ?? '')),
    ];
    $optionsBlock = '';
    foreach ($options as $optLetter => $text) {
        $optionsBlock .= $optLetter . '. ' . ($text !== '' ? $text : '(empty)') . "\n";
    }

    $tutorBlock = $tutorComments !== '' ? $tutorComments : '(none provided)';

    $contextBlock = '';
    $reviewSource = trim((string) ($reviewContext['review_source'] ?? ''));
    if ($reviewSource === 'repaired_preview') {
        $contextBlock .= "\n**Review target:** Repaired preview from Reviewer 1 / AI repair (not yet applied to the saved draft).\n";
        $contextBlock .= "Check whether the repair introduced clinical ambiguity, an unsafe key, or stem–key inconsistency compared with what a tutor would expect from the original draft.\n";
    } else {
        $contextBlock .= "\n**Review target:** Original draft (no repaired preview applied, or repair was blocked).\n";
    }
    $blockedReasons = $reviewContext['repair_blocked_reasons'] ?? [];
    if (is_array($blockedReasons) && $blockedReasons !== []) {
        $reasonLines = [];
        foreach ($blockedReasons as $r) {
            $t = trim((string) $r);
            if ($t !== '') {
                $reasonLines[] = '- ' . $t;
            }
        }
        if ($reasonLines !== []) {
            $contextBlock .= "\n**Automatic repair was blocked** before a repaired preview was created. Reasons:\n"
                . implode("\n", $reasonLines)
                . "\nReview the **original draft** for these safety issues. Do not assume AI repair fixed them.\n";
        }
    }

    return <<<SAFETY_PROMPT
You are an **expert UK clinical safety reviewer** for MSC AKT / MS AKT Single Best Answer items.

You perform a **narrow, strict clinical safety and one-best-answer fairness review only**.

**You do NOT rewrite the question.** You do NOT suggest title wording, lead-in polish, option length changes, or minor MLA style unless they create **clinical ambiguity** or **answer unfairness**.

**You are NOT a style reviewer.** Ignore minor style polish. Do not comment on readiness scores, MLA compliance, or distractor quality except where weak distractors create **clinical ambiguity** or **answer unfairness**.
{$contextBlock}
---

## Step 1 — Independent clinical safety review (read the draft first)

| Element | Content |
|--------|---------|
| Title | {$title} |
| Stem | {$stem} |
| Lead-in | {$leadIn} |
| Options | (see block below) |
| Correct answer | {$letter}. {$correctAnswer} |
| Justification | {$justification} |
| Specialty | {$specialty} |
| Core condition | {$condition} |
| Presentation | {$presentation} |
| Year level | {$yearLevel} |
| Selected skill | {$skill} |
| Tutor comments / objectives | {$tutorBlock} |

**Options (A–E)**
{$optionsBlock}

Assess **only** these clinical safety domains:

1. **Keyed answer clinical correctness** — is the keyed answer clinically correct and complete for this vignette?
2. **Stem–key consistency** — does the stem support the keyed answer; does the justification contradict stem or key?
3. **Definitive investigation vs treatment** — if a diagnosis has been ruled out by a definitive investigation, is it still being treated as present?
   - Example: CTPA shows no PE → anticoagulation for PE is unsafe unless another indication is clearly stated.
4. **Contraindications and safety modifiers** — allergies, pregnancy, renal/hepatic impairment, bleeding risk, recent surgery, drug interactions, and similar.
5. **Prescribing safety** — dose, route, drug choice, duration, and high-risk combinations.
6. **Monitoring logic** — is monitoring appropriate for the drug and scenario?
   - Example: PT/INR/aPTT is **not** routine monitoring for rivaroxaban/apixaban; monitoring should focus on renal function, liver function, FBC, bleeding, adherence, interacting medicines, and ongoing suitability.
7. **Stability-appropriate management** — stable vs unstable presentations managed appropriately for the keyed answer.
8. **One-best-answer fairness** — could more than one option reasonably be correct on this stem?
9. **Faculty review need** — is the item unsafe or clinically unreliable without expert faculty review?

**Calibration (stricter than a general quality reviewer)**

- If the **key is clinically wrong, incomplete, or unsafe**: this is **high priority** — use **clinical_safety_rating** `unsafe` or `needs_faculty_review`, **clinical_accuracy_rating** `unsafe_or_inaccurate`, and list in **high_priority_concerns**.
- If the **key is clinically sound** but distractors are weak or borderline fair: **clinical safety risk is low**; note in **short_summary** that one-best-answer quality may need tutor review — do **not** inflate to unsafe.
- **Hypoxic acute care (CAP, sepsis, asthma, PE, etc.):** when SpO₂ is **clearly below about 92%** on air under a **generic immediate-management** lead-in, flag keys that omit **oxygen therapy** while an option offers **oxygen** — especially **IV fluids plus antibiotics alone** in **severe CAP / hypoxic pneumonia**.
- **Year level** is metadata only — do not penalise difficulty based on year label.

### Oxygen therapy, COPD, and hypercapnia risk (apply when the vignette involves any of these)

Apply this block when the item involves **oxygen therapy**, **COPD**, **risk of hypercapnic respiratory failure**, **hypoxia**, **cyanosis**, **confusion**, **acidosis**, **hypercapnia**, or **respiratory failure** (including oxygen saturation interpretation or oxygen prescribing skills).

Explicitly check:

1. **Controlled oxygen** — where appropriate (especially COPD / CO₂ retainers), is oxygen **controlled** with a **target saturation range** rather than uncontrolled high concentration?
2. **Target range when prescribing or ongoing management** — for **Prescribing**, **Management**, or **Monitoring** items about oxygen, does the keyed answer (when oxygen is correct) include a **target SpO₂ range** (e.g. 88–92% in COPD risk, or 94–98% when that is the teaching point)?
3. **High-flow / non-rebreather justification** — is **high-flow oxygen**, **non-rebreather mask**, or **15 L/min**-style uncontrolled oxygen **justified** by **immediate life-threatening hypoxia** clearly framed in the stem?
   - Do **not** automatically reject all high-flow oxygen in every COPD item.
   - **Do** flag non-rebreather / high-flow oxygen as the **keyed answer** in COPD (or hypercapnia-risk) when the stem shows **confusion**, **severe hypoxia**, **cyanosis**, or **type 2 respiratory failure risk** **without** clear life-threatening hypoxia framing — recommend **faculty review** and note **controlled oxygen**, **target saturations**, and whether **ABG**, **NIV**, or **escalation** belong in the keyed bundle or stem.
4. **Escalation when severity warrants** — when the stem includes **confusion**, **severe hypoxia**, **acidosis**, **hypercapnia**, or **respiratory failure**, consider whether **ABG**, **NIV**, **senior / critical care review**, **ICU escalation**, or **urgent reassessment** should appear in the keyed answer or be acknowledged as missing — flag if absent and clinically expected for the severity painted.
5. **Keyed answer safety in context** — is the **keyed option** safe and complete for this vignette, not only “reasonable oxygen” in isolation?

Record verified issues in **high_priority_concerns** (unsafe key), **prescribing_or_monitoring_concerns** (oxygen targets, devices, monitoring), or **stem_key_consistency_concerns** (severity vs delivery mismatch). Use **needs_faculty_review** when COPD/high-flow oxygen pairing is borderline rather than clearly unsafe.

### VTE / DVT anticoagulation and monitoring (apply when the vignette involves DVT, PE, or VTE treatment)

Check the **keyed answer matches the clinical stage** in the stem:

| Stage in stem | Reasonable key direction (pathway-dependent) |
|---------------|-----------------------------------------------|
| **Imaging delayed** / suspected VTE awaiting confirmation | **Interim therapeutic anticoagulation** (e.g. LMWH) — not a confirmed-DVT long-term DOAC key unless the stem states confirmation |
| **Confirmed DVT / PE, no contraindications** | **DOAC** (e.g. apixaban / rivaroxaban) may be appropriate per local pathway |
| **Renal impairment, pregnancy, cancer, APS, bleeding risk, or contraindication** | **Alternative anticoagulant pathway** — flag keys that ignore modifiers stated in the stem |

**Monitoring:** routine LMWH follow-up is **clinical review, renal function, bleeding, adherence, weight-appropriate dosing** — **not** routine **anti-Xa** unless the stem documents renal impairment, extremes of body weight, pregnancy, bleeding concern, or another **special indication**. Flag **anti-Xa** or **INR** as the keyed routine monitoring answer when unsupported (see `specialist_monitoring_test_keyed_routinely` in faculty notes).

Do **not** reject all DOAC keys in VTE — verify stem–stage consistency and monitoring appropriateness.

---

## Step 2 — Rule-based warnings (clues only; verify against the draft)

Automated warnings may be empty, incomplete, or wrong. Use them **only after** your independent review and **only** if the draft text supports them.

**Rule-based style warnings (clues only — not facts):**
{$warningsJson}

Do **not** copy warning codes into your output. Translate any verified safety-relevant finding into plain English in the appropriate concern array.

---

## Output

Return **valid JSON only** (no markdown fences, no commentary) with **exactly** these keys:

{
  "clinical_safety_rating": "no_major_concerns" | "needs_faculty_review" | "unsafe",
  "clinical_accuracy_rating": "good" | "acceptable_with_minor_edits" | "borderline" | "unsafe_or_inaccurate",
  "one_best_answer_fairness": "good" | "borderline" | "poor",
  "high_priority_concerns": [<strings — wrong/unsafe key, definitive-test contradiction, dangerous prescribing>],
  "prescribing_or_monitoring_concerns": [<strings>],
  "stem_key_consistency_concerns": [<strings>],
  "short_summary": "<2–3 sentences: clinical safety verdict for the tutor; no style nitpicks>",
  "faculty_review_required": <boolean>
}

**clinical_safety_rating guidance:**
- `no_major_concerns` — keyed answer clinically sound; no major safety or fairness issues.
- `needs_faculty_review` — significant clinical ambiguity, borderline key, or fairness concern needing expert review before use.
- `unsafe` — wrong/unsafe keyed answer, management that contradicts a definitive investigation, or dangerous prescribing/monitoring as the keyed answer.

Set **faculty_review_required** true when **clinical_safety_rating** is `needs_faculty_review` or `unsafe`, or when any **high_priority_concerns** exist.

CRITICAL FORMAT RULES:
- Output **one JSON object only**.
- **Do not** wrap in markdown/code fences.
- **Do not** add prose before or after the JSON.
- **Do not** include trailing commentary.

Return JSON only. No extra text.
SAFETY_PROMPT;
}

/**
 * @param list<mixed> $raw
 * @return list<string>
 */
function sbaClinicalSafetyReviewerNormalizeStringList($raw): array
{
    if (!is_array($raw)) {
        return [];
    }
    $out = [];
    foreach ($raw as $item) {
        $t = trim((string) $item);
        if ($t !== '') {
            $out[] = $t;
        }
    }

    return $out;
}

/**
 * @param array<string, mixed> $raw
 * @return array{ok: bool, data: ?array<string, mixed>, error: string}
 */
function normalizeSbaClinicalSafetyReviewerResponse(array $raw): array
{
    $safetyRatings = ['no_major_concerns', 'needs_faculty_review', 'unsafe'];
    $clinical = ['good', 'acceptable_with_minor_edits', 'borderline', 'unsafe_or_inaccurate'];
    $oba = ['good', 'borderline', 'poor'];

    $clinicalSafetyRating = (string) ($raw['clinical_safety_rating'] ?? '');
    if (!in_array($clinicalSafetyRating, $safetyRatings, true)) {
        $clinicalSafetyRating = 'needs_faculty_review';
    }

    $highPriority = sbaClinicalSafetyReviewerNormalizeStringList($raw['high_priority_concerns'] ?? []);
    $prescribing = sbaClinicalSafetyReviewerNormalizeStringList($raw['prescribing_or_monitoring_concerns'] ?? []);
    $stemKey = sbaClinicalSafetyReviewerNormalizeStringList($raw['stem_key_consistency_concerns'] ?? []);

    $facultyRequired = !empty($raw['faculty_review_required']);
    if ($clinicalSafetyRating === 'needs_faculty_review' || $clinicalSafetyRating === 'unsafe') {
        $facultyRequired = true;
    }
    if ($highPriority !== []) {
        $facultyRequired = true;
    }

    $out = [
        'clinical_safety_rating' => $clinicalSafetyRating,
        'clinical_accuracy_rating' => in_array($raw['clinical_accuracy_rating'] ?? '', $clinical, true)
            ? $raw['clinical_accuracy_rating'] : 'borderline',
        'one_best_answer_fairness' => in_array($raw['one_best_answer_fairness'] ?? '', $oba, true)
            ? $raw['one_best_answer_fairness'] : 'borderline',
        'high_priority_concerns' => $highPriority,
        'prescribing_or_monitoring_concerns' => $prescribing,
        'stem_key_consistency_concerns' => $stemKey,
        'short_summary' => trim((string) ($raw['short_summary'] ?? '')),
        'faculty_review_required' => $facultyRequired,
    ];

    if ($out['short_summary'] === '') {
        return ['ok' => false, 'data' => null, 'error' => 'Clinical safety reviewer JSON missing short_summary.'];
    }

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