<?php
// Idempotent Moodle-side configuration for the IILMP integration (SSO + MEL pull).
// Reproduces, as code, the steps we ran by hand in dev so prod (and any rebuild)
// is repeatable. Run on the Moodle container AS THE DAEMON WEB USER, feeding this
// file via stdin (the repo isn't mounted into the Moodle container):
//
//   docker compose -f docker-compose.prod.yml exec -T -u daemon \
//     -e IILMP_BASE_URL=https://iilmp.ruforum.org \
//     -e MOODLE_SSO_CLIENT_ID=moodle-sso \
//     -e MOODLE_SSO_CLIENT_SECRET=<secret> \
//     moodle php /dev/stdin < scripts/configure_moodle_prod.php
//
// It prints exactly one line to STDOUT — "MOODLE_WS_TOKEN=<token>" — for the deploy
// to capture into .env.production. Diagnostics + the (secret-free) summary go to
// STDERR. The OAuth client secret is never printed.
//
// Prereqs: wwwroot must already be https://<moodle-host> with $CFG->sslproxy=true
// (set in config.php by the restore step) and TLS live (real cert) so Moodle's
// OAuth2 discovery of the IILMP issuer succeeds — Moodle rejects http:// issuers.

define('CLI_SCRIPT', true);
require('/opt/bitnami/moodle/config.php');
require_once($CFG->dirroot . '/webservice/lib.php');
require_once($CFG->libdir . '/outputlib.php');

global $DB, $CFG;

function env_required(string $key): string {
    $v = getenv($key);
    if ($v === false || trim($v) === '') {
        fwrite(STDERR, "ERROR: environment variable {$key} is required.\n");
        exit(1);
    }
    return trim($v);
}

// SSO ("Log in with IILMP") env is OPTIONAL. The issuer only runs when Moodle is
// on https (Moodle rejects http:// OAuth2 issuers) AND all three vars are supplied.
// On the AWS-domain HTTP phase these are absent, so we configure only the MEL web
// service + token (which needs no TLS) and skip SSO.
$iilmpbase    = rtrim((string) getenv('IILMP_BASE_URL'), '/');   // e.g. https://iilmp.ruforum.org
$clientid     = trim((string) getenv('MOODLE_SSO_CLIENT_ID'));
$clientsecret = trim((string) getenv('MOODLE_SSO_CLIENT_SECRET'));

$is_https = strpos($CFG->wwwroot, 'https://') === 0;
$do_sso   = $is_https && $iilmpbase !== '' && $clientid !== '' && $clientsecret !== '';
if (!$do_sso) {
    fwrite(STDERR, "NOTE: skipping SSO issuer — "
        . ($is_https ? "IILMP_BASE_URL / MOODLE_SSO_CLIENT_ID / MOODLE_SSO_CLIENT_SECRET not all set"
                     : "wwwroot '{$CFG->wwwroot}' is not https://")
        . ". Configuring the MEL web service + token only.\n");
}

// Admin context so the oauth2 API capability checks pass under CLI.
\core\session\manager::set_user(get_admin());

// --- 1. Login policy -------------------------------------------------------
set_config('sslproxy', $is_https ? 1 : 0);   // 1 only when TLS is terminated upstream
set_config('forcelogin', 1);    // internal platform — no public front page

// --- 2. Web services + REST ------------------------------------------------
set_config('enablewebservices', 1);
$protocols = array_filter(explode(',', (string)($CFG->webserviceprotocols ?? '')));
if (!in_array('rest', $protocols, true)) {
    $protocols[] = 'rest';
    set_config('webserviceprotocols', implode(',', $protocols));
}

// --- 3. "IILMP MEL Pull" external service (Can download files) + functions --
$shortname = 'iilmp_mel_pull';
$service = $DB->get_record('external_services', ['shortname' => $shortname]);
if (!$service) {
    $s = (object)[
        'name' => 'IILMP MEL Pull', 'shortname' => $shortname, 'enabled' => 1,
        'restrictedusers' => 0, 'downloadfiles' => 1, 'uploadfiles' => 0,
        'timecreated' => time(), 'timemodified' => time(),
    ];
    $s->id = $DB->insert_record('external_services', $s);
    $service = $DB->get_record('external_services', ['id' => $s->id]);
} else if (empty($service->downloadfiles)) {
    // downloadfiles is required for the landing-page course thumbnails (pluginfile).
    $service->downloadfiles = 1;
    $service->timemodified = time();
    $DB->update_record('external_services', $service);
}

$functions = [
    'core_webservice_get_site_info',
    'core_course_get_courses',
    'core_course_get_courses_by_field',   // landing catalogue + thumbnails
    'core_course_get_categories',
    'core_enrol_get_enrolled_users',
    'core_completion_get_course_completion_status',
    'mod_quiz_get_quizzes_by_courses',
    'mod_quiz_get_user_attempts',
    'gradereport_user_get_grade_items',
    'mod_feedback_get_feedbacks_by_courses',
    'mod_feedback_get_analysis',
    // IILMP→Moodle role projection (SSO role sync: manager / course creator).
    'core_user_get_users_by_field',
    'core_role_assign_roles',
    'core_role_unassign_roles',
];
foreach ($functions as $fn) {
    if (!$DB->record_exists('external_services_functions',
            ['externalserviceid' => $service->id, 'functionname' => $fn])) {
        $DB->insert_record('external_services_functions',
            (object)['externalserviceid' => $service->id, 'functionname' => $fn]);
    }
}

// --- 4. WS token for the site admin (reused if it already exists) -----------
$admin = get_admin();
$context = context_system::instance();
$existing = $DB->get_record('external_tokens',
    ['externalserviceid' => $service->id, 'userid' => $admin->id]);
if ($existing) {
    $token = $existing->token;
} else if (class_exists('\\core_external\\util') && method_exists('\\core_external\\util', 'generate_token')) {
    $token = \core_external\util::generate_token(EXTERNAL_TOKEN_PERMANENT, $service, $admin->id, $context, 0, '');
} else {
    $token = external_generate_token(EXTERNAL_TOKEN_PERMANENT, $service, $admin->id, $context, 0, '');
}

// --- 5. OAuth2 issuer "Log in with IILMP" + endpoint discovery (SSO only) ---
$issuer = null;
if ($do_sso) {
    $issuer = \core\oauth2\issuer::get_record(['name' => 'Log in with IILMP']);
    if (!$issuer) {
        $issuer = \core\oauth2\api::create_issuer((object)[
            'name' => 'Log in with IILMP',
            'image' => '',                      // NOT NULL; set to the branded icon below
            'baseurl' => $iilmpbase . '/o',
            'clientid' => $clientid,
            'clientsecret' => $clientsecret,
            'loginscopes' => 'openid profile email',
            'loginscopesoffline' => 'openid profile email',
            'showonloginpage' => \core\oauth2\issuer::EVERYWHERE,
            'basicauth' => 0,
            'enabled' => 1,
        ]);
    } else {
        $issuer->set('baseurl', $iilmpbase . '/o');
        $issuer->set('clientid', $clientid);
        $issuer->set('clientsecret', $clientsecret);
        $issuer->set('enabled', 1);
        $issuer->set('showonloginpage', \core\oauth2\issuer::EVERYWHERE);
        $issuer->update();
    }
    // Discover endpoints AND create the field mappings (given_name→firstname, etc.).
    \core\oauth2\discovery\openidconnect::discover_endpoints($issuer);
    $issuer->set('requireconfirmation', 0);     // SSO-provisioned accounts need no email confirm
    $rev = theme_get_revision();
    if ($rev <= 0) { $rev = 1; }
    $issuer->set('image', $CFG->wwwroot . '/theme/image.php/iilmp/theme/' . $rev . '/logo-icon');
    $issuer->update();

    // --- 6. Enable the oauth2 auth plugin + allow account creation ---------
    \core\plugininfo\auth::enable_plugin('oauth2', 1);
    set_config('authpreventaccountcreation', 0);
}

purge_all_caches();

if ($do_sso) {
    fwrite(STDERR, sprintf(
        "Moodle IILMP config applied: wwwroot=%s | issuer id=%d | endpoints=%d | mappings=%d | auth=%s\n",
        $CFG->wwwroot,
        $issuer->get('id'),
        $DB->count_records('oauth2_endpoint', ['issuerid' => $issuer->get('id')]),
        $DB->count_records('oauth2_user_field_mapping', ['issuerid' => $issuer->get('id')]),
        $CFG->auth
    ));
} else {
    fwrite(STDERR, sprintf(
        "Moodle MEL web service configured (SSO skipped): wwwroot=%s | service=%s | downloadfiles=1\n",
        $CFG->wwwroot, $shortname
    ));
}

// The one value the deploy captures — STDOUT only.
echo 'MOODLE_WS_TOKEN=' . $token . "\n";
