<?php
// includes/jupyter_helpers.php
// Centralised helpers for Jupyter configuration and display logic.

/**
 * Returns the default configuration values documented on the Install & Configuration page.
 *
 * @return array<string, string>
 */
function dsp_jupyter_defaults(): array {
    return [
        'base_url' => 'https://localhost',
        'token' => 'dsp-token',
        'workspace_root' => 'datasources',
        'port' => '443',
    ];
}

/**
 * Determines the external base URL for the Jupyter service.
 *
 * @return string
 */
function dsp_jupyter_base_url(): string {
    $configured = getenv('JUPYTER_EXTERNAL_URL');
    if ($configured) {
        return rtrim($configured, '/');
    }

    $defaults = dsp_jupyter_defaults();
    $scheme = (!empty($_SERVER['HTTPS']) && strtolower((string) $_SERVER['HTTPS']) !== 'off') ? 'https' : 'http';
    $hostHeader = $_SERVER['HTTP_HOST'] ?? '';

    if ($hostHeader) {
        $hostname = explode(':', $hostHeader)[0];
        $port = dsp_jupyter_port();
        $authority = $hostname;

        $portIsDefault = ($scheme === 'http' && $port === '80') || ($scheme === 'https' && $port === '443');
        if (!$portIsDefault) {
            $authority .= ':' . $port;
        }

        return sprintf('%s://%s', $scheme, $authority);
    }

    return rtrim($defaults['base_url'], '/');
}

/**
 * Retrieves the token used to authenticate with Jupyter.
 *
 * @return string
 */
function dsp_jupyter_token(): string {
    $authStrategy = strtolower((string) getenv('JUPYTERHUB_AUTH_STRATEGY'));
    if ($authStrategy === 'oauth') {
        return '';
    }

    $defaults = dsp_jupyter_defaults();

    $envToken = getenv('JUPYTER_TOKEN');
    if ($envToken !== false) {
        return $envToken;
    }

    return $defaults['token'];
}

/**
 * Resolves the username JupyterHub should use for the active user.
 *
 * The template can be customised via JUPYTERHUB_USERNAME_TEMPLATE.
 * Supported placeholders:
 *   {person_id}  - numeric person identifier from the session
 *   {username}   - DSP username from the session
 *   {email}      - Session email if available
 *
 * @param int|null $personId Optional explicit person ID
 * @return string|null Sanitised username or null when it cannot be determined.
 */
function dsp_resolve_jupyterhub_username(?int $personId, ?string $username = null, ?string $email = null): ?string {
    if ($personId === null || $personId <= 0) {
        return null;
    }

    $template = getenv('JUPYTERHUB_USERNAME_TEMPLATE') ?: 'user_{person_id}';
    $usernameRaw = str_replace(
        ['{person_id}', '{username}', '{email}'],
        [
            (string) $personId,
            (string) $username,
            (string) $email,
        ],
        $template
    );

    $usernameSanitised = preg_replace('/[^a-zA-Z0-9._-]+/', '-', $usernameRaw);
    $usernameSanitised = trim((string) $usernameSanitised, "-_.");

    return $usernameSanitised !== '' ? $usernameSanitised : null;
}

function dsp_jupyterhub_username(?int $personId = null): ?string {
    if ($personId === null) {
        $personId = isset($_SESSION['person_id']) ? (int) $_SESSION['person_id'] : null;
    }

    $username = $_SESSION['username'] ?? null;
    $email = $_SESSION['email'] ?? null;

    return dsp_resolve_jupyterhub_username($personId, $username, $email);
}

/**
 * Builds the per-user route served by JupyterHub.
 *
 * The path template can be overridden with JUPYTERHUB_USER_PATH (e.g. "user/{username}/lab").
 *
 * @param string $baseUrl   Hub base URL.
 * @param int|null $personId Optional explicit person ID.
 * @return string Absolute path including the user segment, without trailing slash.
 */
function dsp_jupyterhub_user_route(string $baseUrl, ?int $personId = null): string {
    $baseUrl = rtrim($baseUrl, '/');

    $pathTemplate = getenv('JUPYTERHUB_USER_PATH');
    if ($pathTemplate === false || $pathTemplate === '') {
        return $baseUrl;
    }

    $personId = $personId ?? (isset($_SESSION['person_id']) ? (int) $_SESSION['person_id'] : null);
    $username = dsp_jupyterhub_username($personId);

    if ($username === null) {
        return $baseUrl;
    }

    $relativePath = str_replace(
        ['{username}', '{person_id}'],
        [$username, (string) $personId],
        ltrim($pathTemplate, '/')
    );

    return rtrim($baseUrl . '/' . $relativePath, '/');
}

/**
 * Builds the iframe URL using the resolved base URL and token.
 *
 * @param string|null $baseUrl Optional override of the base URL.
 * @param string|null $token   Optional override of the token.
 * @param int|null    $personId Optional override of the person ID used for the route.
 *
 * @return string
 */
function dsp_jupyter_iframe_url(?string $baseUrl = null, ?string $token = null, ?int $personId = null): string {
    $resolvedBase = rtrim($baseUrl ?: dsp_jupyter_base_url(), '/');
    $userRoute = dsp_jupyterhub_user_route($resolvedBase, $personId);
    $finalToken = $token ?: dsp_jupyter_token();

    return $finalToken
        ? sprintf('%s?token=%s', $userRoute, urlencode($finalToken))
        : $userRoute;
}

/**
 * Determines the host port the Jupyter service is published on.
 *
 * @return string
 */
function dsp_jupyter_port(): string {
    $configured = getenv('JUPYTER_PORT');
    if ($configured === false || $configured === '') {
        $configured = getenv('JUPYTERHUB_PORT');
    }
    if ($configured) {
        return (string) $configured;
    }

    $defaults = dsp_jupyter_defaults();

    return $defaults['port'];
}

/**
 * Captures the environment overrides impacting the embedded Jupyter configuration.
 *
 * @return array<string, string|null>
 */
function dsp_jupyter_env_overrides(): array {
    return [
        'JUPYTER_EXTERNAL_URL' => getenv('JUPYTER_EXTERNAL_URL') ?: null,
        'JUPYTER_TOKEN' => getenv('JUPYTER_TOKEN') ?: null,
        'JUPYTER_PORT' => getenv('JUPYTER_PORT') ?: null,
        'JUPYTERHUB_PORT' => getenv('JUPYTERHUB_PORT') ?: null,
        'DSP_APP_ORIGINS' => getenv('DSP_APP_ORIGINS') ?: null,
        'DSP_FRAME_ANCESTORS' => getenv('DSP_FRAME_ANCESTORS') ?: null,
        'JUPYTERHUB_USERNAME_TEMPLATE' => getenv('JUPYTERHUB_USERNAME_TEMPLATE') ?: null,
        'JUPYTERHUB_USER_PATH' => getenv('JUPYTERHUB_USER_PATH') ?: null,
    ];
}
