<?php

/**
 * Progress Analytics — AI narrative (P4, premium).
 *
 * Turns the numbers the query library already computed into a short, factual
 * summary a headteacher can read at a glance ("Basic 5 fell 8% in Mathematics,
 * driven by the exam component"). The model is given ONLY the computed figures
 * and is instructed never to invent numbers — the narrative is a rewrite of the
 * data, not a new analysis.
 *
 * Premium: layered on the RBC AI engine (ai_agent / ai_analytics). The endpoint
 * gates on those modules; this file just builds the prompt and calls the engine.
 */

if (!function_exists('getDBConnection')) {
    require_once dirname(__DIR__, 2) . '/config.php';
}
require_once dirname(__DIR__) . '/lib/progress_query.php';
require_once dirname(__DIR__, 2) . '/ai/provider_engine.php';

/**
 * Assemble the compact factual brief handed to the model. Everything here is a
 * real computed figure — the prompt explicitly forbids the model from adding
 * any number not present in this text.
 */
function progressInsightBrief(mysqli $conn, array $scope): string
{
    $kpis     = progressKpis($conn, $scope);
    $subjects = progressSubjectBreakdown($conn, $scope);
    $trend    = progressTrend($conn, $scope);
    $dist     = progressGradeDistribution($conn, $scope);

    $scopeLabel = match ($scope['level']) {
        'student' => 'an individual student',
        'class'   => 'class ' . (implode(', ', $scope['classes']) ?: '(unspecified)'),
        default   => 'the whole school',
    };
    $period = ($scope['term'] ?: 'all terms')
        . ($scope['academic_year'] !== '' ? ', ' . $scope['academic_year'] : '');

    $lines = [];
    $lines[] = "SCOPE: {$scopeLabel}. PERIOD: {$period}.";
    $lines[] = sprintf(
        "OVERALL: average %s, pass rate %s%% (pass mark %s), top %s, lowest %s, %d results across %d students.",
        $kpis['avg_score'] ?? 'n/a',
        $kpis['pass_rate'] ?? 'n/a',
        // number_format first so there is always a decimal point to trim back to
        // (a bare "50" would otherwise lose its trailing zero and read as "5").
        rtrim(rtrim(number_format((float) $kpis['pass_mark'], 2, '.', ''), '0'), '.'),
        $kpis['top_score'] ?? 'n/a',
        $kpis['low_score'] ?? 'n/a',
        $kpis['results'],
        $kpis['students']
    );
    if ($kpis['coverage_pct'] !== null && $kpis['coverage_pct'] < 90) {
        $lines[] = "DATA COVERAGE: only {$kpis['coverage_pct']}% of students have marks entered — averages may be provisional.";
    }

    // Trend across periods (primary series).
    if (!empty($trend['labels'])) {
        $pairs = [];
        $series0 = $trend['series'][0]['data'] ?? [];
        foreach ($trend['labels'] as $i => $lbl) {
            $v = $series0[$i] ?? null;
            $pairs[] = $lbl . '=' . ($v === null ? 'n/a' : $v);
        }
        $lines[] = "TREND (avg per term): " . implode(', ', $pairs) . '.';
    }

    // Strongest / weakest subjects (top and bottom of the ranked list).
    if ($subjects !== []) {
        $fmt = fn($s) => $s['subject'] . ' ' . ($s['avg_score'] ?? 'n/a');
        $top = array_slice($subjects, 0, 3);
        $bottom = array_slice($subjects, -3);
        $lines[] = "STRONGEST SUBJECTS: " . implode(', ', array_map($fmt, $top)) . '.';
        $lines[] = "WEAKEST SUBJECTS: " . implode(', ', array_map($fmt, array_reverse($bottom))) . '.';
    }

    // Grade spread.
    if (!empty($dist['labels'])) {
        $g = [];
        foreach ($dist['labels'] as $i => $lbl) {
            $g[] = $lbl . ':' . ($dist['counts'][$i] ?? 0);
        }
        $lines[] = "GRADE SPREAD: " . implode(', ', $g) . " (total {$dist['total']}).";
    }

    // Cohort movement (school/class only).
    if ($scope['level'] !== 'student') {
        $mv = progressRankMovement($conn, $scope);
        if ($mv['to'] !== null && ($mv['improved'] !== [] || $mv['declined'] !== [])) {
            $imp = array_map(fn($d) => $d['name'] . ' +' . $d['delta'], array_slice($mv['improved'], 0, 3));
            $dec = array_map(fn($d) => $d['name'] . ' ' . $d['delta'], array_slice($mv['declined'], 0, 3));
            $lines[] = "MOVEMENT {$mv['from']['label']}→{$mv['to']['label']}: most improved "
                . (implode(', ', $imp) ?: 'none') . "; most declined " . (implode(', ', $dec) ?: 'none') . '.';
        }
    }

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

/**
 * Generate the narrative. Returns
 *   ['success'=>bool, 'narrative'=>?string, 'provider'=>?string, 'error'=>?string].
 *
 * @param bool $hasData false when the scope produced no results — skips the AI
 *                      call entirely (nothing to summarise).
 */
function progressInsightGenerate(mysqli $conn, array $scope): array
{
    $kpis = progressKpis($conn, $scope);
    if ((int) $kpis['results'] === 0) {
        return ['success' => false, 'narrative' => null, 'provider' => null,
                'error' => 'No results in this selection to summarise.'];
    }

    $brief = progressInsightBrief($conn, $scope);

    $system = "You are an assistant to the head of a Ghanaian basic/JHS school, summarising "
        . "academic progress analytics. Write a concise, plain-English briefing a busy head "
        . "can read in 20 seconds. RULES: use ONLY the figures in the DATA block — never invent "
        . "or estimate a number that is not given. Refer to Ghanaian terms/grading naturally. "
        . "Lead with the single most important takeaway. Note improvements and concerns evenly. "
        . "If data coverage is flagged as provisional, say the figures are early. Do NOT give "
        . "generic teaching advice; stay specific to these numbers. Output 3-5 short sentences "
        . "or tight bullet points, no preamble, no headings.";

    $prompt = "DATA:\n" . $brief . "\n\nWrite the briefing now.";

    $res = RBCAIEngine::generate($prompt, $system, 500, false);

    if (!($res['success'] ?? false)) {
        return ['success' => false, 'narrative' => null, 'provider' => null,
                'error' => 'The AI service is unavailable right now. Please try again shortly.'];
    }

    return [
        'success'   => true,
        'narrative' => trim((string) $res['content']),
        'provider'  => $res['provider'] ?? null,
        'error'     => null,
    ];
}

/** True when the current license includes an AI module the narrative can use. */
function progressInsightAvailable(): bool
{
    return function_exists('hasModule')
        && (hasModule('ai_agent') || hasModule('ai_analytics'));
}
