<?php

declare(strict_types=1);

require_once __DIR__ . '/prompt_variant.php';

/**
 * Variant-only review/repair model — mirrors main SBA 5.1 reviewer name (read-only; does not change shared config).
 */
function variantOpenAiReviewModel(): string
{
    if (defined('OPENAI_VARIANT_REVIEW_MODEL')) {
        $m = trim((string) OPENAI_VARIANT_REVIEW_MODEL);
        if ($m !== '') {
            return $m;
        }
    }

    if (defined('OPENAI_SBA_REVIEW_MODEL')) {
        $m = trim((string) OPENAI_SBA_REVIEW_MODEL);
        if ($m !== '') {
            return $m;
        }
    }

    return 'gpt-5.1';
}

/**
 * Whether automatic repair should run from normalized review scores.
 *
 * @param array<string, mixed> $review
 */
function variantShouldRunRepair(array $review): bool
{
    if (!empty($review['repair_recommended'])) {
        return true;
    }

    if (($review['same_tested_concept'] ?? '') !== 'yes') {
        return true;
    }
    if (($review['correct_answer_preserved'] ?? '') !== 'yes') {
        return true;
    }
    if (($review['difference_from_original'] ?? '') !== 'appropriate') {
        return true;
    }
    if (($review['single_best_answer'] ?? '') !== 'yes') {
        return true;
    }
    if (($review['distractor_quality'] ?? '') === 'major_issues') {
        return true;
    }
    if (($review['ms_akt_style'] ?? '') === 'major_issues') {
        return true;
    }
    if (($review['clinical_safety'] ?? '') !== 'no_concerns') {
        return true;
    }
    if (($review['distractor_quality'] ?? '') === 'minor_issues') {
        return true;
    }
    if (($review['ms_akt_style'] ?? '') === 'minor_issues') {
        return true;
    }

    $issues = $review['issues'] ?? [];
    if (is_array($issues) && count($issues) > 0) {
        return true;
    }

    return false;
}

/**
 * @param array<string, mixed> $sourceQuestion { row_number?, data? }
 * @param array<string, mixed> $variant DB or API question row
 */
function buildVariantAdvisoryReviewPrompt(array $sourceQuestion, array $variant): string
{
    $data = is_array($sourceQuestion['data'] ?? null) ? $sourceQuestion['data'] : [];
    $rowNumber = (string) ($sourceQuestion['row_number'] ?? '');

    $questionTitle = embedVariantField($data['Question title'] ?? '');
    $questionText = embedVariantField($data['Question text'] ?? '');
    $comments = embedVariantField($data['Comments'] ?? '');
    $examinerNotes = embedVariantField($data['Examiner notes'] ?? '');
    $coreCondition = embedVariantField($data['Core condition'] ?? '');
    $presentation = embedVariantField($data['Presentation'] ?? '');
    $skill = embedVariantField($data['Skill'] ?? '');
    $specialty = embedVariantField($data['Specialty'] ?? '');
    $summativeFormative = embedVariantField($data['Summative/Formative'] ?? '');
    $year = embedVariantField($data['Year'] ?? '');
    $stemSeed = embedVariantField($data['Stem'] ?? '');
    $correctAnswer = embedVariantField($data['Correct answer'] ?? '');
    $correctAnswerLetter = embedVariantField($data['Correct answer letter'] ?? '');
    $learningOutcome = embedVariantField(
        $data['Learning outcome'] ?? $data['Learning outcomes'] ?? $data['Learning Outcome'] ?? ''
    );
    $appliedKnowledge = embedVariantField($data['Applied knowledge'] ?? $data['Applied Knowledge'] ?? '');
    $careSetting = embedVariantField($data['Care setting'] ?? $data['Care Setting'] ?? '');
    $justificationSeed = embedVariantField($data['Justification'] ?? $data['justification'] ?? '');

    $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);

    $metaBlock = implode("\n", [
        variantPromptMetaLine('Skill', $skill),
        variantPromptMetaLine('Core condition', $coreCondition),
        variantPromptMetaLine('Presentation', $presentation),
        variantPromptMetaLine('Specialty', $specialty),
        variantPromptMetaLine('Learning outcome(s)', $learningOutcome),
        variantPromptMetaLine('Applied knowledge', $appliedKnowledge),
        variantPromptMetaLine('Care setting', $careSetting),
        variantPromptMetaLine('Summative/Formative', $summativeFormative),
        variantPromptMetaLine('Year', $year),
    ]);

    $vTitle = embedVariantField($variant['title'] ?? '');
    $vStem = embedVariantField($variant['stem'] ?? '');
    $vLeadIn = embedVariantField($variant['lead_in'] ?? '');
    $vJust = embedVariantField($variant['justification'] ?? '');
    $vLetter = embedVariantField($variant['correct_answer_letter'] ?? '');
    $vAnswer = embedVariantField($variant['correct_answer'] ?? '');
    $vA = embedVariantField($variant['option_a'] ?? '', 2000);
    $vB = embedVariantField($variant['option_b'] ?? '', 2000);
    $vC = embedVariantField($variant['option_c'] ?? '', 2000);
    $vD = embedVariantField($variant['option_d'] ?? '', 2000);
    $vE = embedVariantField($variant['option_e'] ?? '', 2000);

    return <<<PROMPT
You are an expert UK medical school item reviewer performing a **strict pre-repair** quality check on the **first-pass generated variant** of an existing SBA question, before optional automatic repair.

**CRITICAL**
- You are reviewing the **first generated draft only**, not any later repaired version.
- This review does **not** approve the question for export or use.
- You must **not** change, rewrite, or replace the variant text in your output.
- **Tutor review** remains the final approval step after any automatic repair.
- Your findings may be used to trigger automatic repair; they describe the draft **before** repair.
- Be **strict**: flag minor MS AKT style issues, weak distractors, vague investigations, answer-concept drift, and items too similar or too different from the source.
- Set **repair_recommended** to true when automatic repair should fix MLA/MS AKT style, clinical accuracy, answer concept, distractors, or wording.
- Return **valid JSON only** (no markdown fences, no prose outside JSON).

**MISSING METADATA**
- The source may lack learning outcomes, tags, or formal metadata (e.g. simple form imports).
- Use metadata below when provided; if marked **(not provided)**, infer the tested knowledge point, clinical concept, task type and reasoning step from the source **stem/question text, options, correct answer and justification**.
- Treat the source **correct answer** and **justification** (if present) as the strongest clues when metadata is absent.
- Do **not** invent formal learning outcomes, curriculum codes, or tags in your JSON.

**YOUR TASK**
Compare the **SOURCE** (original uploaded item) with the **VARIANT** (newly generated item). Assess whether the variant is a fair MS AKT-style variant: clinically equivalent in what is tested, sufficiently different in surface details, one clearly best answer, plausible homogeneous distractors, MS AKT style, and safe.

Assess specifically:
1. **same_tested_concept** — Does the variant test the same underlying knowledge point, reasoning step, or misconception?
2. **correct_answer_preserved** — Is the correct answer **concept** preserved (allow re-lettering and rewording of the keyed option)?
3. **difference_from_original** — too_similar | appropriate | too_different | unclear
4. **single_best_answer** — Exactly one clearly best option on the variant vignette?
5. **distractor_quality** — Plausible, homogeneous, fair distractors?
6. **ms_akt_style** — pass | minor_issues | major_issues (see MS AKT rules below)
7. **clinical_safety** — no_concerns | possible_concern | major_concern
8. **tutor_review_priority** — low | medium | high (how urgently a tutor should review before export)
9. **summary** — Short plain-English summary for a tutor (2–4 sentences max).
10. **issues** — Array of short issue strings (empty array if none).
11. **suggested_edits** — Array of short suggestions for repair (what should be fixed); never full replacement text blocks.
12. **repair_recommended** — true if the variant should undergo automatic repair (style, clinical accuracy, answer concept, distractors, difference from source, or safety concerns that are likely fixable).

**MS AKT / MLA AKT STYLE (check the VARIANT)**
- Present tense, third person clinical stem; age and gender at start where appropriate (e.g. “A 45 year old woman…”; no hyphenated age).
- No patient names; presenting problem in first sentence.
- Concise stem, usually ~30–100 words unless clearly needs more; no extraneous details.
- Simple wording (“start” not “commence”; “has” not “presents with” / “complains of”).
- Avoid “known to have”, “diagnosed with”, “with a history of”.
- Avoid “On examination”.
- Observations order: temperature, pulse, BP, respiratory rate, oxygen saturation; “pulse” not “pulse rate”.
- “oxygen saturation is …% breathing air”, not “on room air”.
- Actual investigation values with reference ranges where possible, not vague summaries.
- Lead-in: “What?” for most; avoid negative lead-ins (“least likely”); lead-in should pass cover tests (infer task without options; cannot answer without stem).
- Five options only; plausible, homogeneous, concise, sentence case; British spelling; UK terminology; generic drug names; eponyms without possessive apostrophes (e.g. Down syndrome).
- No unsupported clinical facts in the variant; no ambiguous or unsafe keyed answer.

**SOURCE METADATA**
{$metaBlock}
- Examiner notes: {$examinerNotes}
- Comments: {$comments}
- Source justification: {$justificationSeed}

**SOURCE CONTENT (row {$rowNumber})**
- Title: {$questionTitle}
- Question text / stem context: {$questionText}
- Separate stem field if any: {$stemSeed}
- Correct answer letter (concept): {$correctAnswerLetter}
- Correct answer text (concept): {$correctAnswer}
- Options: A: {$seedOptA} | B: {$seedOptB} | C: {$seedOptC} | D: {$seedOptD} | E: {$seedOptE}

**VARIANT CONTENT**
- Title: {$vTitle}
- Stem: {$vStem}
- Lead-in: {$vLeadIn}
- Options: A: {$vA} | B: {$vB} | C: {$vC} | D: {$vD} | E: {$vE}
- Correct answer: {$vLetter} — {$vAnswer}
- Justification: {$vJust}

OUTPUT — return this JSON object only:

{
  "same_tested_concept": "yes | no | unclear",
  "correct_answer_preserved": "yes | no | unclear",
  "difference_from_original": "too_similar | appropriate | too_different | unclear",
  "single_best_answer": "yes | no | unclear",
  "distractor_quality": "good | minor_issues | major_issues | unclear",
  "ms_akt_style": "pass | minor_issues | major_issues",
  "clinical_safety": "no_concerns | possible_concern | major_concern",
  "tutor_review_priority": "low | medium | high",
  "summary": "string",
  "issues": ["string"],
  "suggested_edits": ["string"],
  "repair_recommended": true,
  "advisory_only": true,
  "do_not_auto_apply": true
}

Return JSON only.
PROMPT;
}

/**
 * @param array<string, mixed> $raw
 * @return array{ok: bool, data: ?array<string, mixed>, error: string}
 */
function normalizeVariantAdvisoryReviewResponse(array $raw): array
{
    $yesNo = ['yes', 'no', 'unclear'];
    $difference = ['too_similar', 'appropriate', 'too_different', 'unclear'];
    $quality = ['good', 'minor_issues', 'major_issues', 'unclear'];
    $style = ['pass', 'minor_issues', 'major_issues'];
    $safety = ['no_concerns', 'possible_concern', 'major_concern'];
    $priority = ['low', 'medium', 'high'];

    $pick = static function (array $allowed, $value, string $default) {
        $v = strtolower(trim((string) $value));

        return in_array($v, $allowed, true) ? $v : $default;
    };

    $summary = trim((string) ($raw['summary'] ?? ''));
    if ($summary === '') {
        return ['ok' => false, 'data' => null, 'error' => 'Reviewer JSON missing summary.'];
    }

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

    $suggestedEdits = [];
    if (isset($raw['suggested_edits']) && is_array($raw['suggested_edits'])) {
        foreach ($raw['suggested_edits'] as $item) {
            $t = trim((string) $item);
            if ($t !== '') {
                $suggestedEdits[] = $t;
            }
        }
    }

    $repairRecommended = filter_var($raw['repair_recommended'] ?? false, FILTER_VALIDATE_BOOLEAN);

    $out = [
        'same_tested_concept' => $pick($yesNo, $raw['same_tested_concept'] ?? '', 'unclear'),
        'correct_answer_preserved' => $pick($yesNo, $raw['correct_answer_preserved'] ?? '', 'unclear'),
        'difference_from_original' => $pick($difference, $raw['difference_from_original'] ?? '', 'unclear'),
        'single_best_answer' => $pick($yesNo, $raw['single_best_answer'] ?? '', 'unclear'),
        'distractor_quality' => $pick($quality, $raw['distractor_quality'] ?? '', 'unclear'),
        'ms_akt_style' => $pick($style, $raw['ms_akt_style'] ?? '', 'minor_issues'),
        'clinical_safety' => $pick($safety, $raw['clinical_safety'] ?? '', 'no_concerns'),
        'tutor_review_priority' => $pick($priority, $raw['tutor_review_priority'] ?? '', 'medium'),
        'summary' => $summary,
        'issues' => $issues,
        'suggested_edits' => $suggestedEdits,
        'repair_recommended' => $repairRecommended,
        'advisory_only' => true,
        'do_not_auto_apply' => true,
    ];

    if (variantShouldRunRepair($out)) {
        $out['repair_recommended'] = true;
    }

    if (($out['clinical_safety'] ?? '') === 'major_concern' && $out['tutor_review_priority'] === 'low') {
        $out['tutor_review_priority'] = 'high';
    }
    if (
        ($out['same_tested_concept'] ?? '') === 'no'
        || ($out['correct_answer_preserved'] ?? '') === 'no'
        || ($out['difference_from_original'] ?? '') === 'too_different'
    ) {
        if ($out['tutor_review_priority'] === 'low') {
            $out['tutor_review_priority'] = 'medium';
        }
    }

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