<?php

/**
 * Verify AI reviewer prompt structure and optional live review (sepsis + non-sepsis).
 * Usage: php tools/test_ai_reviewer_independent_review.php
 */

require dirname(__DIR__) . '/prompts/sba_ai_reviewer_prompt.php';
require dirname(__DIR__) . '/validators/style_validator.php';

function assertContains(string $haystack, string $needle, string $label): void
{
    if (stripos($haystack, $needle) === false) {
        echo 'FAIL: ' . $label . ' (missing: ' . $needle . ')' . PHP_EOL;
        exit(1);
    }
    echo 'OK: ' . $label . PHP_EOL;
}

function assertOrder(string $haystack, string $first, string $second, string $label): void
{
    $p1 = stripos($haystack, $first);
    $p2 = stripos($haystack, $second);
    if ($p1 === false || $p2 === false || $p1 >= $p2) {
        echo 'FAIL: ' . $label . PHP_EOL;
        exit(1);
    }
    echo 'OK: ' . $label . PHP_EOL;
}

$sepsisQuestion = [
    'specialty' => 'Acute Medicine',
    'condition_name' => 'Sepsis',
    'presentation' => 'Septic shock',
    'skill' => 'Emergency Management',
    'year_level' => 'MLA Final Year',
    'summative_formative' => 'Summative',
    'title' => 'Initial septic shock resuscitation',
    'stem' => 'A 68 year old man attends the emergency department. His temperature is 39.1°C, pulse 118/min, blood pressure 82/48 mmHg, respiratory rate 24/min and oxygen saturation 96% on breathing air. No IV fluids or antibiotics have been administered yet.',
    'lead_in' => 'What is the most appropriate immediate management?',
    'option_a' => 'Start IV fluids and broad-spectrum IV antibiotics',
    'option_b' => 'Start vasopressors before adequate fluid resuscitation',
    'option_c' => 'Give oral antibiotics and observe',
    'option_d' => 'Arrange critical care review without starting treatment',
    'option_e' => 'Repeat lactate before treating persistent hypotension',
    'correct_answer_letter' => 'A',
    'correct_answer' => 'Start IV fluids and broad-spectrum IV antibiotics',
    'justification' => 'Hypotensive septic shock requires immediate IV fluids and broad-spectrum IV antibiotics.',
];

$diabetesQuestion = [
    'specialty' => 'General Practice',
    'condition_name' => 'Type 2 diabetes mellitus',
    'presentation' => 'Routine review',
    'skill' => 'Management',
    'year_level' => 'MLA Final Year',
    'summative_formative' => 'Formative',
    'title' => 'Type 2 diabetes monitoring',
    'stem' => 'A 58 year old woman with type 2 diabetes attends for routine review. She has no symptoms. Her HbA1c is 62 mmol/mol and blood pressure is 132/78 mmHg. She takes metformin 1 g twice daily.',
    'lead_in' => 'What is the most appropriate next management step?',
    'option_a' => 'Add a sodium-glucose cotransporter-2 inhibitor',
    'option_b' => 'Stop metformin and observe',
    'option_c' => 'Arrange urgent same-day hospital admission',
    'option_d' => 'Request chest X-ray',
    'option_e' => 'Start basal insulin immediately without further assessment',
    'correct_answer_letter' => 'A',
    'correct_answer' => 'Add a sodium-glucose cotransporter-2 inhibitor',
    'justification' => 'HbA1c above target on metformin alone supports intensification with an SGLT2 inhibitor when clinically appropriate.',
];

$falseSepsisWarning = [[
    'code' => 'sepsis.emergency_incomplete_key_without_narrow_lead_in',
    'severity' => 'high',
    'message' => 'Test false positive for scepticism',
]];

$sepsisPrompt = buildSbaAiReviewerPrompt($sepsisQuestion, $falseSepsisWarning, []);
$diabetesPrompt = buildSbaAiReviewerPrompt($diabetesQuestion, [], []);

echo '=== Prompt structure (sepsis) ===' . PHP_EOL;
assertContains($sepsisPrompt, 'not a rule-warning summariser', 'anti-summariser instruction');
assertContains($sepsisPrompt, 'Step 1 — Independent review', 'step 1 independent review');
assertContains($sepsisPrompt, 'Step 3 — Compare with rule-based warnings', 'step 3 warnings');
assertOrder($sepsisPrompt, 'Step 1 — Independent review', 'Rule-based style warnings', 'draft before warnings');
assertOrder($sepsisPrompt, 'Step 1 — Independent review', 'Step 3 — Compare with rule-based warnings', 'steps before warnings section');
assertContains($sepsisPrompt, 'any specialty', 'specialty-agnostic scope');
assertContains($sepsisPrompt, 'independent_concerns', 'independent_concerns schema');

echo PHP_EOL . '=== Prompt structure (non-sepsis diabetes) ===' . PHP_EOL;
assertContains($diabetesPrompt, 'Type 2 diabetes mellitus', 'diabetes condition in prompt');
assertOrder($diabetesPrompt, 'Step 1 — Independent review', 'Rule-based style warnings', 'diabetes draft before warnings');
if (stripos($diabetesPrompt, 'Optional — sepsis Emergency Management') !== false) {
    echo 'FAIL: sepsis addendum should not appear for non-sepsis diabetes' . PHP_EOL;
    exit(1);
}
echo 'OK: no sepsis addendum on non-sepsis question' . PHP_EOL;

echo PHP_EOL . '=== Normalizer alias fields ===' . PHP_EOL;
$norm = normalizeSbaAiReviewerResponse([
    'overall_readiness_percent' => 80,
    'mla_compliance_percent' => 78,
    'clinical_accuracy_rating' => 'acceptable_with_minor_edits',
    'one_best_answer_rating' => 'good',
    'skill_alignment_rating' => 'good',
    'agreed_rule_warnings' => ['uk.on_breathing_air'],
    'possible_false_positive_warnings' => ['sepsis.emergency_incomplete_key — stem supports combined key'],
    'additional_ai_concerns' => ['Distractor C is too obvious'],
    'short_tutor_summary' => 'Usable draft with minor distractor polish.',
    'recommended_changes' => [],
]);
if (!$norm['ok']) {
    echo 'FAIL: normalizer ' . $norm['error'] . PHP_EOL;
    exit(1);
}
$r = $norm['data'];
if ($r['agreed_rule_warning_codes'] !== ['uk.on_breathing_air']) {
    echo 'FAIL: agreed alias merge' . PHP_EOL;
    exit(1);
}
if ($r['independent_concerns'] !== ['Distractor C is too obvious']) {
    echo 'FAIL: additional_ai_concerns alias' . PHP_EOL;
    exit(1);
}
echo 'OK: schema aliases normalized' . PHP_EOL;

$configPath = dirname(__DIR__) . '/app/config/config.php';
require $configPath;
$apiKey = defined('OPENAI_API_KEY') ? (string) OPENAI_API_KEY : '';
if ($apiKey === '' || $apiKey === 'your-openai-api-key-here') {
    echo PHP_EOL . 'SKIP: live AI review (no OpenAI API key configured)' . PHP_EOL;
    echo 'Prompt structure tests passed.' . PHP_EOL;
    exit(0);
}

require dirname(__DIR__) . '/app/ai/form_generator_retry.php';

$acsQuestion = [
    'specialty' => 'Cardiology',
    'condition_name' => 'Acute coronary syndrome',
    'presentation' => 'Chest pain',
    'skill' => 'Interpretation',
    'year_level' => 'MLA Final Year',
    'summative_formative' => 'Summative',
    'title' => 'ACS ECG interpretation',
    'stem' => 'A 62 year old man has central chest pain for 2 hours. His ECG shows ST depression in leads V4–V6. High-sensitivity troponin is elevated above the 99th centile URL. He has no ST elevation.',
    'lead_in' => 'What is the most likely diagnosis?',
    'option_a' => 'Non-ST elevation myocardial infarction',
    'option_b' => 'ST elevation myocardial infarction',
    'option_c' => 'Stable angina',
    'option_d' => 'Unstable angina with normal troponin',
    'option_e' => 'Non-cardiac chest pain',
    'correct_answer_letter' => 'A',
    'correct_answer' => 'Non-ST elevation myocardial infarction',
    'justification' => 'Elevated troponin with ischaemic ECG changes without ST elevation supports NSTEMI rather than STEMI, stable angina, or normal-troponin unstable angina.',
];

$acsWarnings = [[
    'code' => 'options.high_similarity.option_a_option_b',
    'severity' => 'warning',
    'message' => 'Options may be too similar (test false positive for related ACS diagnoses)',
]];

foreach ([
    'sepsis_emergency' => [$sepsisQuestion, $falseSepsisWarning],
    'acs_interpretation' => [$acsQuestion, $acsWarnings],
] as $label => [$q, $warnings]) {
    echo PHP_EOL . '=== Live AI review: ' . $label . ' ===' . PHP_EOL;
    $prompt = buildSbaAiReviewerPrompt($q, $warnings, []);
    $fetch = formGeneratorOpenAiChatJsonQuestion(
        $prompt,
        '',
        0,
        0.35,
        formGeneratorOpenAiSbaReviewModel()
    );
    if (!$fetch['ok']) {
        echo 'FAIL: ' . $fetch['error'] . PHP_EOL;
        continue;
    }
    $parsed = normalizeSbaAiReviewerResponse($fetch['data']);
    if (!$parsed['ok']) {
        echo 'FAIL: ' . $parsed['error'] . PHP_EOL;
        continue;
    }
    $review = $parsed['data'];
    echo 'Readiness: ' . $review['overall_readiness_percent'] . '%' . PHP_EOL;
    echo 'Clinical: ' . $review['clinical_accuracy_rating'] . PHP_EOL;
    echo 'Summary: ' . $review['short_tutor_summary'] . PHP_EOL;
    echo 'Agreed warnings: ' . implode(', ', $review['agreed_rule_warning_codes']) . PHP_EOL;
    echo 'False positives: ' . implode('; ', $review['possible_false_positive_rule_warning_codes']) . PHP_EOL;
    echo 'Independent: ' . implode('; ', $review['independent_concerns']) . PHP_EOL;
    if ($label === 'sepsis_emergency'
        && in_array('sepsis.emergency_incomplete_key_without_narrow_lead_in', $review['agreed_rule_warning_codes'], true)) {
        echo 'WARN: agreed with likely false sepsis incomplete-key warning' . PHP_EOL;
    }
    if (in_array($review['clinical_accuracy_rating'], ['unsafe_or_inaccurate'], true)
        && $review['overall_readiness_percent'] < 65) {
        echo 'WARN: scored harshly despite sound key (check calibration)' . PHP_EOL;
    }
    if ($label === 'acs_interpretation'
        && in_array('options.high_similarity.option_a_option_b', $review['agreed_rule_warning_codes'], true)) {
        echo 'WARN: agreed with high_similarity for distinct NSTEMI vs STEMI' . PHP_EOL;
    }
    $weakDistractorRec = false;
    foreach ($review['recommended_changes'] as $chg) {
        if (($chg['field'] ?? '') === 'options' && strlen((string) ($chg['suggested_change'] ?? '')) > 40) {
            $weakDistractorRec = true;
        }
    }
    if (!$weakDistractorRec && in_array($label, ['sepsis_emergency', 'acs_interpretation'], true)) {
        echo 'NOTE: no detailed distractor concepts in recommendations (optional)' . PHP_EOL;
    }
    if (distractorSuggestionsLookBad($review)) {
        echo 'WARN: recommended_changes contain forbidden distractor concept' . PHP_EOL;
    } else {
        echo 'OK: no forbidden distractor phrases in recommendations' . PHP_EOL;
    }
    foreach ($review['recommended_changes'] as $chg) {
        if (($chg['field'] ?? '') === 'options') {
            echo '  options suggestion: ' . substr((string) ($chg['suggested_change'] ?? ''), 0, 200) . PHP_EOL;
        }
    }
}

echo PHP_EOL . '=== Distractor suggestion guidance in prompts ===' . PHP_EOL;
$calPrompt = buildSbaAiReviewerPrompt($sepsisQuestion, [], []);
assertContains($calPrompt, 'culture-based antibiotic delay', 'sepsis forbidden distractor');
assertContains($calPrompt, 'start vasopressors before adequate fluid resuscitation', 'sepsis good distractor');
$acsPrompt = buildSbaAiReviewerPrompt($acsQuestion, [], []);
assertContains($acsPrompt, 'unstable angina with elevated troponin', 'ACS forbidden distractor');
assertContains($acsPrompt, 'ACS Interpretation / Diagnosis', 'ACS addendum');

function distractorSuggestionsLookBad(array $review): bool
{
    $blob = strtolower(json_encode($review['recommended_changes'] ?? [], JSON_UNESCAPED_UNICODE));
    $forbiddenPhrases = [
        'until culture',
        'await culture',
        'culture result',
        'withhold antibiot',
        'pending culture',
        'unstable angina with elevated troponin',
        'unstable angina with raised troponin',
    ];
    foreach ($forbiddenPhrases as $f) {
        if (str_contains($blob, $f)) {
            return true;
        }
    }

    return false;
}

echo PHP_EOL . 'Done.' . PHP_EOL;
