<?php

/**
 * Deterministic pre-generation scenario plan for sepsis Emergency Management (main SBA generator).
 */

$formSkillsPath = dirname(__DIR__) . '/app/ai/form_generator_default_skills.php';
if (is_readable($formSkillsPath)) {
    require_once $formSkillsPath;
}

function sbaSepsisNormalizeScenarioSlotKey(string $slot): string
{
    $s = strtolower(trim($slot));
    if ($s === 'lactate_abdominal_source') {
        return 'abdominal_source_control';
    }

    return $s;
}

/**
 * @return list<string>
 */
function sbaSepsisSlotsOrderedByPresentationAffinity(string $presentation): array
{
    if (!function_exists('sbaSepsisEmergencyScenarioSlotKeys')) {
        require_once __DIR__ . '/sba_sepsis_batch_concepts.php';
    }

    $affinity = sbaSepsisPresentationAffinityScores($presentation);
    $slots = sbaSepsisEmergencyScenarioSlotKeys();
    usort($slots, static function (string $a, string $b) use ($affinity): int {
        $sa = $affinity[$a] ?? 0;
        $sb = $affinity[$b] ?? 0;
        if ($sa !== $sb) {
            return $sb <=> $sa;
        }

        return strcmp($a, $b);
    });

    return $slots;
}

/**
 * @param list<array<string, mixed>> $priorRows
 * @return list<string>
 */
function sbaSepsisEmergencySlotsFromPriorRows(array $priorRows): array
{
    if (!function_exists('sbaSepsisInferEmergencyScenarioCategory')) {
        require_once __DIR__ . '/sba_sepsis_batch_concepts.php';
    }

    $slots = [];
    foreach ($priorRows as $p) {
        if (!is_array($p) || !preg_match('/^emergency\s+management$/i', trim((string) ($p['skill'] ?? '')))) {
            continue;
        }
        $tags = (string) ($p['tags'] ?? '');
        if (preg_match('/\bsepsis_emergency_slot=([a-z_]+)/i', $tags, $m)) {
            $slots[] = sbaSepsisNormalizeScenarioSlotKey($m[1]);
            continue;
        }
        $stem = trim((string) ($p['stem'] ?? ''));
        $lead = trim((string) ($p['lead_in'] ?? ''));
        $keyed = trim((string) ($p['correct_answer'] ?? ''));
        if ($keyed === '') {
            continue;
        }
        $slots[] = sbaSepsisNormalizeScenarioSlotKey(
            sbaSepsisInferEmergencyScenarioCategory($stem, $lead, $keyed)
        );
    }

    return $slots;
}

/**
 * @param array<string, int> $slotUseCounts
 * @return array{slot: string, repeat_cycle: int}
 */
function sbaSepsisSelectNextUnusedEmergencySlot(string $presentation, array $slotUseCounts): array
{
    $ordered = sbaSepsisSlotsOrderedByPresentationAffinity($presentation);

    foreach ($ordered as $slot) {
        if (($slotUseCounts[$slot] ?? 0) === 0) {
            return ['slot' => $slot, 'repeat_cycle' => 0];
        }
    }

    $minUse = min(array_merge([PHP_INT_MAX], array_values($slotUseCounts)));
    if ($minUse === PHP_INT_MAX) {
        $minUse = 0;
    }

    foreach ($ordered as $slot) {
        if (($slotUseCounts[$slot] ?? 0) === $minUse) {
            return ['slot' => $slot, 'repeat_cycle' => $minUse];
        }
    }

    return ['slot' => 'initial_resuscitation', 'repeat_cycle' => 0];
}

/**
 * @param list<array<string, mixed>> $priorRows
 * @return array{used_slots: list<string>, used_concepts: list<string>, slot_counts: array<string, int>}
 */
function sbaSepsisEmergencyBatchUsageSummary(array $priorRows): array
{
    $usedSlots = [];
    $usedConcepts = [];
    $slotCounts = [];

    foreach ($priorRows as $p) {
        if (!is_array($p) || !preg_match('/^emergency\s+management$/i', trim((string) ($p['skill'] ?? '')))) {
            continue;
        }
        $tags = (string) ($p['tags'] ?? '');
        $keyed = trim((string) ($p['correct_answer'] ?? ''));
        if (preg_match('/\bsepsis_emergency_slot=([a-z_]+)/i', $tags, $m)) {
            $slot = sbaSepsisNormalizeScenarioSlotKey($m[1]);
        } elseif ($keyed !== '' && function_exists('sbaSepsisInferEmergencyScenarioCategory')) {
            $slot = sbaSepsisNormalizeScenarioSlotKey(sbaSepsisInferEmergencyScenarioCategory(
                trim((string) ($p['stem'] ?? '')),
                trim((string) ($p['lead_in'] ?? '')),
                $keyed
            ));
        } else {
            continue;
        }
        $usedSlots[] = $slot;
        $slotCounts[$slot] = ($slotCounts[$slot] ?? 0) + 1;
        if ($keyed !== '') {
            $usedConcepts[] = $keyed;
        }
    }

    return [
        'used_slots' => $usedSlots,
        'used_concepts' => $usedConcepts,
        'slot_counts' => $slotCounts,
    ];
}

/**
 * @return array{emergency_question_numbers: list<int>, emergency_total: int, emergency_ordinal: int, current_question_number: int}
 */
function sbaSepsisJobEmergencyQuestionContext(array $job): array
{
    $skillsCsv = (string) ($job['_job_skills'] ?? $job['skills'] ?? '');
    $skills = array_values(array_filter(array_map('trim', explode(',', $skillsCsv))));
    if ($skills === []) {
        $skills = ['Emergency Management'];
    }

    $numQuestions = max(1, (int) ($job['num_questions'] ?? 1));
    $currentQ = max(1, (int) ($job['questions_completed'] ?? 0) + 1);
    $emergencyQs = [];
    $ordinal = 0;

    for ($i = 1; $i <= $numQuestions; ++$i) {
        $sk = formGeneratorSkillForQuestionNumber($skills, $i);
        if (!preg_match('/^emergency\s+management$/i', $sk)) {
            continue;
        }
        $emergencyQs[] = $i;
        if ($i <= $currentQ) {
            ++$ordinal;
        }
    }

    return [
        'emergency_question_numbers' => $emergencyQs,
        'emergency_total' => count($emergencyQs),
        'emergency_ordinal' => $ordinal,
        'current_question_number' => $currentQ,
    ];
}

function sbaSepsisEmergencyScenarioPlanApplies(array $job): bool
{
    $skill = trim((string) ($job['skill'] ?? ''));
    if (!preg_match('/^emergency\s+management$/i', $skill)) {
        return false;
    }
    if (!function_exists('sbaGeneratorConditionLooksSepsis')) {
        require_once __DIR__ . '/sba_sepsis_batch_concepts.php';
    }

    return sbaGeneratorConditionLooksSepsis((string) ($job['condition_name'] ?? ''));
}

/**
 * @return array<string, int>
 */
function sbaSepsisPresentationAffinityScores(string $presentation): array
{
    if (!function_exists('sbaSepsisEmergencyScenarioSlotKeys')) {
        require_once __DIR__ . '/sba_sepsis_batch_concepts.php';
    }

    $p = mb_strtolower(trim($presentation));
    $scores = [];
    foreach (sbaSepsisEmergencyScenarioSlotKeys() as $slot) {
        $scores[$slot] = 10;
    }

    if ($p === '' || preg_match('/\b(?:septic\s+shock|shock|sepsis)\b/i', $p)) {
        $scores['initial_resuscitation'] += 30;
    }

    if (preg_match('/\b(?:obstruct(?:ed|ion)?|hydronephrosis|pyelonephritis|infected\s+stone|renal\s+stone|flank\s+pain|obstructed\s+kidney)\b/i', $p)) {
        $scores['source_control'] += 50;
    }
    if (preg_match('/\b(?:refractory|persistent\s+hypotension|noradrenaline|vasopressor|after\s+(?:adequate\s+)?fluids|fluid[\s-]refractory)\b/i', $p)) {
        $scores['refractory_hypotension'] += 48;
    }
    if (preg_match('/\b(?:hypox|hypoxaemia|hypoxemia|low\s+oxygen|breathless)\b/i', $p)
        || preg_match('/\b(?:spo2|oxygen\s+saturation).{0,30}(?:8[0-9]|9[01])\s*%/i', $p)) {
        $scores['hypoxic_escalation'] += 48;
    }
    if (preg_match('/\b(?:periton|perforat|abdominal\s+(?:pain|sepsis)|rigidity|collection|appendic|cholecyst|biliary|post[\s-]?operative)\b/i', $p)) {
        $scores['abdominal_source_control'] += 46;
    }

    return $scores;
}

/**
 * @return array<string, mixed>
 */
function sbaSepsisEmergencyScenarioPlanSpec(string $slot, int $repeatCycle): array
{
    if (!function_exists('sbaSepsisEmergencyScenarioDisplayLabel')) {
        require_once __DIR__ . '/sba_sepsis_batch_concepts.php';
    }

    $slot = sbaSepsisNormalizeScenarioSlotKey($slot);
    $repeatNote = $repeatCycle > 0
        ? '**Repeat cycle:** use a new infection source, setting, stem cues, lead-in, key wording, and distractors — do not copy a prior item.'
        : '';

    $specs = match ($slot) {
        'initial_resuscitation' => [
            'stem_cues' => [
                '**No IV fluids or broad-spectrum IV antibiotics started yet.** Unstable septic shock.',
                'Observations in **MS AKT order** where used: temperature, pulse, blood pressure, respiratory rate, oxygen saturation.',
                'Avoid SpO₂ below 94% unless **oxygen is included in the keyed answer**.',
            ],
            'lead_in_focus' => 'Varied **immediate management** wording (not copied from prior batch lead-ins).',
            'required_key_concept' => '**IV fluids plus broad-spectrum IV antibiotics** (or explicit sepsis resuscitation bundle).',
            'prohibited_key_concepts' => [
                'Noradrenaline/vasopressor (untreated shock).',
                'Fluids/antibiotics alone when SpO₂ is clearly low without oxygen in the key.',
            ],
            'forbidden_distractor_lines' => [
                'Oxygen therapy only when hypoxia is relevant.',
                'Withhold antibiotics until cultures; oral antibiotics and observe; monitor without treatment.',
            ],
        ],
        'refractory_hypotension' => [
            'stem_cues' => [
                '**Adequate IV fluids and broad-spectrum IV antibiotics already given** (state explicitly).',
                '**Persistent hypotension** despite treatment.',
            ],
            'lead_in_focus' => '**Next circulatory support** / **next step for persistent hypotension** — not generic immediate management.',
            'required_key_concept' => '**Noradrenaline/vasopressor** plus **critical care / ICU** involvement.',
            'prohibited_key_concepts' => [
                'Repeat “start IV fluids and broad-spectrum IV antibiotics”.',
            ],
            'forbidden_distractor_lines' => [
                'Withhold antibiotics until cultures; oral antibiotics and observe; oxygen therapy only; monitor without treatment.',
            ],
        ],
        'source_control' => [
            'stem_cues' => [
                '**Hydronephrosis, infected stone, obstruction, or obstructed kidney already identified** in the stem (not “request scan to find obstruction”).',
                '**IV fluids and broad-spectrum IV antibiotics already given or ongoing.**',
            ],
            'lead_in_focus' => '**In addition to sepsis resuscitation**, what is the **most important next step** / **additional urgent management**?',
            'required_key_concept' => '**Urgent urological intervention** or **source control** (drainage/decompression) — management wording.',
            'prohibited_key_concepts' => [
                'Investigation-only keys (e.g. request urgent ultrasound to assess).',
                'Initial fluids-plus-antibiotics bundle.',
            ],
            'forbidden_distractor_lines' => [
                'Withhold antibiotics until cultures; monitor without treatment; arrange review without treatment.',
            ],
        ],
        'abdominal_source_control' => [
            'stem_cues' => [
                '**Abdominal pain with peritonism**, suspected **perforation**, **collection**, or post-operative abdominal sepsis.',
                '**IV fluids and broad-spectrum IV antibiotics already given or ongoing.**',
            ],
            'lead_in_focus' => '**Next urgent escalation** / **additional management** for abdominal source — vary lead-in wording.',
            'required_key_concept' => '**Urgent surgical review** or **source-control intervention** (management wording).',
            'prohibited_key_concepts' => [
                'Investigation-only keys unless skill were Investigation.',
                'Urinary obstruction / nephrostomy keys (wrong source family).',
            ],
            'forbidden_distractor_lines' => [
                'Repeat lactate only; monitor saturation only; antipyretics and reassess only.',
            ],
        ],
        'hypoxic_escalation' => [
            'stem_cues' => [
                '**SpO₂ clearly low** (below 92% on breathing air, or below 94% with acute respiratory compromise) with septic shock cues — **not** normal saturations such as 96%.',
            ],
            'lead_in_focus' => 'Immediate management — vary wording; must address **hypoxia** fairly.',
            'required_key_concept' => 'If **no antibiotics yet** in stem: **oxygen plus IV fluids plus broad-spectrum IV antibiotics**. If **antibiotics already given**: **oxygen plus** ongoing resuscitation/escalation (fluids, critical care, vasopressor as stem supports).',
            'prohibited_key_concepts' => [
                'Oxygen alone as keyed answer.',
                'Fluids/antibiotics alone when SpO₂ is **clinically low** (<92%, or <94% with respiratory compromise).',
            ],
            'forbidden_distractor_lines' => [
                'Oxygen therapy only; monitor saturation only.',
            ],
        ],
        default => [
            'stem_cues' => ['Unstable sepsis emergency vignette.'],
            'lead_in_focus' => 'MS AKT emergency management lead-in.',
            'required_key_concept' => 'Category-appropriate urgent management.',
            'prohibited_key_concepts' => [],
            'forbidden_distractor_lines' => [],
        ],
    };

    $distractorGuidance = [
        '**Plausible wrong actions only** — similar option length; avoid full stops at end of options unless all options use them.',
        'Examples: further crystalloid without reassessing responsiveness; broaden antibiotics without addressing shock/source; ward review not ICU; delay source control until BP normalises; repeat lactate before treating persistent hypotension; vasopressor without critical care; continue treatment without escalation; request non-urgent review; source control when stem has no source cue; vasopressor before fluids when no fluids given yet.',
    ];

    $styleNotes = [
        'Avoid “history of”, “observations show”, “His observations are:”, “vital signs”, “underlying issue”.',
        'Neutral title — not “Management of …”.',
        'Vary lead-in from prior emergency items.',
    ];
    if ($repeatNote !== '') {
        $styleNotes[] = $repeatNote;
    }

    return [
        'slot' => $slot,
        'label' => sbaSepsisEmergencyScenarioDisplayLabel($slot),
        'repeat_cycle' => $repeatCycle,
        'stem_cues' => $specs['stem_cues'],
        'lead_in_focus' => $specs['lead_in_focus'],
        'required_key_concept' => $specs['required_key_concept'],
        'prohibited_key_concepts' => $specs['prohibited_key_concepts'],
        'forbidden_distractor_lines' => $specs['forbidden_distractor_lines'],
        'distractor_guidance' => $distractorGuidance,
        'style_notes' => $styleNotes,
    ];
}

/**
 * Deterministic plan for all Emergency Management questions in the job (locks past items from tags).
 *
 * @return array<int, array<string, mixed>>
 */
function sbaSepsisBuildFullEmergencyJobScenarioPlan(array $job): array
{
    if (!sbaSepsisEmergencyScenarioPlanApplies($job)) {
        return [];
    }

    $ctx = sbaSepsisJobEmergencyQuestionContext($job);
    $presentation = trim((string) ($job['presentation'] ?? ''));
    $priors = $job['_batch_prior_questions'] ?? [];
    $priorRows = is_array($priors) ? $priors : [];

    $lockedPriorSlots = sbaSepsisEmergencySlotsFromPriorRows($priorRows);
    $slotUseCounts = [];
    foreach ($lockedPriorSlots as $s) {
        $slotUseCounts[$s] = ($slotUseCounts[$s] ?? 0) + 1;
    }

    $plan = [];
    $priorIdx = 0;
    $ordinal = 0;

    foreach ($ctx['emergency_question_numbers'] as $qNum) {
        ++$ordinal;
        if ($priorIdx < count($lockedPriorSlots)) {
            $slot = $lockedPriorSlots[$priorIdx];
            ++$priorIdx;
            $repeatCycle = max(0, ($slotUseCounts[$slot] ?? 1) - 1);
        } else {
            $pick = sbaSepsisSelectNextUnusedEmergencySlot($presentation, $slotUseCounts);
            $slot = $pick['slot'];
            $repeatCycle = $pick['repeat_cycle'];
            $slotUseCounts[$slot] = ($slotUseCounts[$slot] ?? 0) + 1;
        }

        $item = sbaSepsisEmergencyScenarioPlanSpec($slot, $repeatCycle);
        $item['emergency_ordinal'] = $ordinal;
        $item['emergency_total'] = $ctx['emergency_total'];
        $item['question_number'] = $qNum;
        $plan[$qNum] = $item;
    }

    return $plan;
}

/**
 * @return ?array<string, mixed>
 */
function sbaSepsisResolveEmergencyScenarioPlanItem(array $job): ?array
{
    if (!sbaSepsisEmergencyScenarioPlanApplies($job)) {
        return null;
    }

    if (!empty($job['_sepsis_emergency_scenario_plan']) && is_array($job['_sepsis_emergency_scenario_plan'])) {
        return $job['_sepsis_emergency_scenario_plan'];
    }

    $full = sbaSepsisBuildFullEmergencyJobScenarioPlan($job);
    $qNum = max(1, (int) ($job['questions_completed'] ?? 0) + 1);

    return $full[$qNum] ?? null;
}

/**
 * @param array<string, mixed> $job
 */
function buildSbaGeneratorSepsisEmergencyScenarioPlanBlock(array $job): string
{
    $item = sbaSepsisResolveEmergencyScenarioPlanItem($job);
    if ($item === null) {
        return '';
    }

    $priors = $job['_batch_prior_questions'] ?? [];
    $usage = sbaSepsisEmergencyBatchUsageSummary(is_array($priors) ? $priors : []);
    $usedSlotLabels = [];
    foreach (array_unique($usage['used_slots']) as $us) {
        $usedSlotLabels[] = function_exists('sbaSepsisEmergencyScenarioDisplayLabel')
            ? sbaSepsisEmergencyScenarioDisplayLabel($us) . ' (`' . $us . '`)'
            : $us;
    }

    $qNum = (int) $item['question_number'];
    $lines = [];
    $lines[] = 'BINDING — ASSIGNED SEPSIS EMERGENCY SCENARIO (deterministic plan — mandatory)';
    $lines[] = 'You **must** write this item for the assigned category only. **Do not** reuse categories or keyed concepts listed as already used.';
    $lines[] = '';
    $lines[] = '**This item:** Emergency #' . (int) $item['emergency_ordinal'] . ' of ' . (int) $item['emergency_total']
        . ' (job question #' . $qNum . ').';
    $lines[] = '**Assigned category (locked):** ' . (string) $item['label'] . ' — slot `' . (string) $item['slot'] . '`.';

    if ($usedSlotLabels !== []) {
        $lines[] = '**Categories already used in this batch (forbidden until all five have been used once):** ' . implode('; ', $usedSlotLabels) . '.';
    } else {
        $lines[] = '**Categories already used in this batch:** none yet.';
    }

    if ($usage['used_concepts'] !== []) {
        $lines[] = '**Answer concepts already used (do not repeat wording or clinical idea):**';
        foreach ($usage['used_concepts'] as $concept) {
            $lines[] = '- “' . $concept . '”';
        }
    }

    $lines[] = '';
    $lines[] = '**Required stem cues:**';
    foreach ($item['stem_cues'] as $cue) {
        $lines[] = '- ' . $cue;
    }
    $lines[] = '**Required lead-in focus:** ' . (string) $item['lead_in_focus'];
    $lines[] = '**Required correct-answer concept:** ' . (string) $item['required_key_concept'];
    $lines[] = '**Prohibited keyed concepts:**';
    foreach ($item['prohibited_key_concepts'] as $ban) {
        $lines[] = '- ' . $ban;
    }
    $lines[] = '**Forbidden distractor lines (do not use):**';
    foreach ($item['forbidden_distractor_lines'] as $fd) {
        $lines[] = '- ' . $fd;
    }
    $lines[] = '**Distractor guidance:**';
    foreach ($item['distractor_guidance'] as $dg) {
        $lines[] = '- ' . $dg;
    }
    $lines[] = '**Style:**';
    foreach ($item['style_notes'] as $sn) {
        $lines[] = '- ' . $sn;
    }

    $full = sbaSepsisBuildFullEmergencyJobScenarioPlan($job);
    if (count($full) > 1) {
        $lines[] = '';
        $lines[] = '**Full job emergency plan (do not take another item’s slot):**';
        foreach ($full as $pq => $pItem) {
            $marker = ((int) $pq === $qNum) ? ' ← **THIS ITEM**' : '';
            $lines[] = '- Q' . $pq . ': `' . (string) $pItem['slot'] . '`' . $marker;
        }
    }

    return "\n" . embedPromptField(implode("\n", $lines), 9000) . "\n";
}

function sbaSepsisEmergencyScenarioPlanTagFragment(?string $slot): string
{
    if ($slot === null || $slot === '') {
        return '';
    }

    return 'sepsis_emergency_slot=' . sbaSepsisNormalizeScenarioSlotKey($slot);
}
