<?php
session_start();
require_once __DIR__ . '/config.php';
require_once __DIR__ . '/includes/auth.php';
require_once __DIR__ . '/includes/jupyter_helpers.php';

redirect_if_not_logged_in('index.php');
redirect_if_not_role('DAC Staff', 'index.php');

$jupyterDefaults = dsp_jupyter_defaults();
$resolvedBaseUrl = dsp_jupyter_base_url();
$resolvedToken = dsp_jupyter_token();
$resolvedPort = dsp_jupyter_port();
$envOverrides = dsp_jupyter_env_overrides();
$workspaceBaseMessage = $jupyterDefaults['workspace_root'];

if (!empty($_SESSION['person_id'])) {
    $workspaceBaseMessage = sprintf(
        '%s/user_%d',
        rtrim($jupyterDefaults['workspace_root'], '/'),
        (int) $_SESSION['person_id']
    );
}

$activeJupyterOverrides = array_filter(
    $envOverrides,
    static fn($value) => $value !== null && $value !== ''
);
?>
<!DOCTYPE html>
<html lang="en">
<?php include_once __DIR__ . '/includes/header_admin.php'; ?>
<body>
    <div class="wrapper">
        <?php include_once __DIR__ . '/includes/nav_admin.php'; ?>
        <div class="main-content">
            <nav class="navbar navbar-expand-lg navbar-light bg-light mb-4 rounded-3">
                <div class="container-fluid">
                    <a class="navbar-brand" href="#">Install &amp; Configuration</a>
                    <div class="d-flex">
                        <span class="navbar-text text-muted">
                            Signed in as <?php echo htmlspecialchars($_SESSION['username'] ?? ''); ?>
                        </span>
                    </div>
                </div>
            </nav>

            <?php if (isset($_SESSION['message'])): ?>
                <div class="alert alert-<?php echo htmlspecialchars($_SESSION['message_type'] ?? 'info'); ?> alert-dismissible fade show rounded-pill" role="alert">
                    <?php echo htmlspecialchars($_SESSION['message']); ?>
                    <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
                </div>
                <?php
                unset($_SESSION['message'], $_SESSION['message_type']);
                ?>
            <?php endif; ?>

            <section class="mb-4">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-primary">Before You Start</h2>
                        <ul class="mb-0 text-muted">
                            <li>Install the latest <strong>Docker Desktop</strong> (or Docker Engine with the Compose plugin) and reboot if prompted.</li>
                            <li>Ensure at least <strong>2 GB</strong> of free disk space for base images and seed data.</li>
                            <li>Confirm your account has access to the repository in the organisation’s source control system.</li>
                        </ul>
                    </div>
                </div>
            </section>

            <section class="mb-4">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-success">Quick Setup</h2>
                        <ol class="mb-0 text-muted">
                            <li class="mb-2">Copy and unzip: <code>&lt;dsp&gt;</code> and <code>cd dsp</code>.</li>
                            <li class="mb-2">Copy any provided <code>.env</code> templates if custom credentials are required.</li>
                            <li class="mb-2">Bring the stack online with <code>docker-compose up --build</code>.</li>
                            <li class="mb-2">Wait for the first run to import <code>db/niph_dsps.sql</code> into MySQL automatically.</li>
                            <li class="mb-0">Visit each service to confirm connectivity (see table below).</li>
                        </ol>
                    </div>
                </div>
            </section>

            <section class="mb-4" id="data-ecosystem">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-secondary">Understanding the Data Ecosystem</h2>
                        <p class="text-muted">
                            The Docker stack wires the PHP/Apache portal, MySQL database, phpMyAdmin console, and R-enabled Jupyter service together.
                            Shared bind mounts ensure uploaded datasets and vetted R scripts stay identical across runtime services.
                        </p>
                        <div class="row row-cols-1 row-cols-lg-2 g-4">
                            <div class="col">
                                <div class="border rounded h-100 p-3 bg-light-subtle">
                                    <h3 class="h6 text-uppercase text-muted">Platform Architecture</h3>
                                    <ul class="mb-0 text-muted small">
                                        <li><code>dsp_app</code> serves dashboards on port 8082 and talks to MySQL over the internal network.</li>
                                        <li><code>dsp_db</code> seeds from <code>db/niph_dsps.sql</code> on first boot and exposes port 3307 for host access.</li>
                                        <li><code>dsp_phpmyadmin</code> and <code>dsp_jupyter</code> connect to the same database/files so admins can troubleshoot or run reproducible analytics.</li>
                                    </ul>
                                </div>
                            </div>
                            <div class="col">
                                <div class="border rounded h-100 p-3 bg-light-subtle">
                                    <h3 class="h6 text-uppercase text-muted">Data Lifecycle &amp; Governance</h3>
                                    <ul class="mb-0 text-muted small">
                                        <li><code>dsps_tbl_datasource</code> binds each dataset to its owner (<code>fkisp_id_of</code>), type, category, filenames, and publication state.</li>
                                        <li><code>dsps_tbl_datasource_permission</code> logs read/download/analyze approvals while <code>dsps_tbl_datasource_used</code> tracks downstream usage.</li>
                                        <li><code>ist_tbl_people</code> and <code>ist_tbl_users</code> provide identity, roles, and the <code>isu_can_run_r</code> capability flag for analytics features.</li>
                                    </ul>
                                </div>
                            </div>
                        </div>
                        <div class="mt-4">
                            <h3 class="h6 text-uppercase text-muted">Diagram Reference</h3>
                            <div class="text-center">
                                <img src="assets/images/niph_dsp_data_ecosystem.png" alt="NIPH DSP data ecosystem overview" class="img-fluid rounded border shadow-sm">
                                <div class="mt-3">
                                    <button type="button" class="btn btn-sm btn-outline-secondary" data-bs-toggle="modal" data-bs-target="#ecosystemDiagramModal">
                                        <i class="fas fa-search-plus me-1"></i>Expand diagram
                                    </button>
                                    <a class="btn btn-sm btn-outline-primary ms-2" href="assets/images/niph_dsp_data_ecosystem.png" download>
                                        <i class="fas fa-download me-1"></i>Download PNG
                                    </a>
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </section>

            <section class="mb-4">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-info">Service Endpoints</h2>
                        <div class="table-responsive">
                            <table class="table table-striped table-bordered align-middle mb-0">
                                <thead class="table-light">
                                    <tr>
                                        <th scope="col">Service</th>
                                        <th scope="col">URL</th>
                                        <th scope="col">Notes</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td>PHP Application</td>
                                        <td><code>http://localhost:8082</code></td>
                                        <td>Uses credentials defined in <code>docker-compose.yml</code>.</td>
                                    </tr>
                                    <tr>
                                        <td>phpMyAdmin</td>
                                        <td><code>http://localhost:8081</code></td>
                                        <td>Login with <code>dsp_user/dsp_pass</code> or MySQL root credentials.</td>
                                    </tr>
                                    <tr>
                                        <td>Jupyter (R)</td>
                                        <td><code>http://localhost:8888</code></td>
                                        <td>Authenticate with token <code>dsp-token</code>.</td>
                                    </tr>
                                    <tr>
                                        <td>MySQL (host access)</td>
                                        <td><code>localhost:3307</code></td>
                                        <td>Database <code>niph_dsps</code>, user <code>dsp_user/dsp_pass</code>.</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </section>

            <section class="mb-4">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-warning">Configuration Checklist</h2>
                        <p class="text-muted">Update the following environment variables in <code>docker-compose.yml</code> (or host environment) to match your deployment:</p>
                        <div class="table-responsive">
                            <table class="table table-bordered align-middle mb-0">
                                <thead class="table-light">
                                    <tr>
                                        <th scope="col">Variable</th>
                                        <th scope="col">Description</th>
                                        <th scope="col">Default</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td><code>DB_HOST</code></td>
                                        <td>Database hostname reachable from the PHP container.</td>
                                        <td><code>mysql</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>DB_PORT</code></td>
                                        <td>MySQL port exposed inside the container.</td>
                                        <td><code>3306</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>DB_NAME</code></td>
                                        <td>Name of the primary DSP database.</td>
                                        <td><code>niph_dsps</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>DB_USER</code></td>
                                        <td>Application database username.</td>
                                        <td><code>dsp_user</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>DB_PASS</code></td>
                                        <td>Application database password.</td>
                                        <td><code>dsp_pass</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>RSCRIPT_PATH</code></td>
                                        <td>Override if <code>Rscript</code> is not located at the system default.</td>
                                        <td><code>/usr/bin/Rscript</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTER_EXTERNAL_URL</code></td>
                                        <td>Base URL embedded in the portal when exposing Jupyter on a custom host or domain.</td>
                                        <td><code>https://localhost</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTERHUB_PORT</code></td>
                                        <td>Published host port for the JupyterHub ingress.</td>
                                        <td><code>443</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTER_TOKEN</code></td>
                                        <td>Legacy token for standalone Jupyter deployments.</td>
                                        <td><code>(empty)</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_APP_ORIGINS</code></td>
                                        <td>Space-separated origins allowed to call Jupyter APIs (CORS).</td>
                                        <td><code>http://localhost:8082 http://127.0.0.1:8082</code></td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_FRAME_ANCESTORS</code></td>
                                        <td>Space-separated origins permitted to embed Jupyter in an iframe.</td>
                                        <td><code>http://localhost:8082 http://127.0.0.1:8082</code></td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </section>

            <section class="mb-4" id="r-in-jupyter-service">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-info">R in JupyterHub Service</h2>
                        <p class="text-muted">
                            The <code>dsp_jupyterhub</code> service launches per-user JupyterLab containers through JupyterHub.
                            These defaults mirror the values exposed in the in-app JupyterHub Service Reference so you can verify overrides in <code>.env</code> or infrastructure tooling.
                        </p>
                        <div class="table-responsive mb-4">
                            <table class="table table-bordered align-middle">
                                <thead class="table-light">
                                    <tr>
                                        <th scope="col">Setting</th>
                                        <th scope="col">Default</th>
                                        <th scope="col">How to Override</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td>Notebook Base URL</td>
                                        <td><code>https://localhost</code></td>
                                        <td>Set <code>JUPYTER_EXTERNAL_URL</code> (or configure your reverse proxy) when publishing under a different host or scheme.</td>
                                    </tr>
                                    <tr>
                                        <td>Published Port</td>
                                        <td><code>443</code></td>
                                        <td>Update the <code>${JUPYTERHUB_PORT:-443}:8000</code> mapping in <code>docker-compose.yml</code> or export <code>JUPYTERHUB_PORT</code> in your <code>.env</code>.</td>
                                    </tr>
                                    <tr>
                                        <td>Authentication Token</td>
                                        <td><code>(managed by OAuth)</code></td>
                                        <td>OAuth replaces static tokens; keep <code>JUPYTER_TOKEN</code> empty when using JupyterHub.</td>
                                    </tr>
                                    <tr>
                                        <td>Workspace Mount</td>
                                        <td><code>datasources/user_{person_id}</code></td>
                                        <td>Mounted from <code>./uploads/jupyter_workspace</code>; adjust the volume in <code>docker-compose.yml</code> if you relocate storage.</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <h3 class="h6 text-uppercase text-muted mb-3">Environment Override Guidance</h3>
                        <div class="table-responsive mb-4">
                            <table class="table table-sm table-striped align-middle mb-0">
                                <thead class="table-light">
                                    <tr>
                                        <th scope="col">Variable</th>
                                        <th scope="col">Purpose</th>
                                        <th scope="col">Notes</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td><code>JUPYTER_EXTERNAL_URL</code></td>
                                        <td>Overrides the base URL surfaced in the portal and iframe embeds.</td>
                                        <td>Leave empty to fall back to the detected hostname and <code>JUPYTERHUB_PORT</code>.</td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTERHUB_PORT</code></td>
                                        <td>Sets the host port used when constructing external URLs.</td>
                                        <td>Must align with the published port mapping in <code>docker-compose.yml</code> (fallback to <code>JUPYTER_PORT</code> for legacy deployments).</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_APP_ORIGINS</code></td>
                                        <td>Extends the CORS allow list for DSP web origins calling notebook APIs.</td>
                                        <td>Include every host that loads the embedded notebook via XHR.</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_FRAME_ANCESTORS</code></td>
                                        <td>Controls the Content-Security-Policy <code>frame-ancestors</code> directive for notebook iframes.</td>
                                        <td>Match the origins defined in <code>DSP_APP_ORIGINS</code> (and any admin hostnames).</td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTERHUB_USERNAME_TEMPLATE</code></td>
                                        <td>Pattern used to map DSP accounts to JupyterHub usernames.</td>
                                        <td>Defaults to <code>user_{person_id}</code>. Placeholders: <code>{person_id}</code>, <code>{username}</code>, <code>{email}</code>. Only used when <code>JUPYTERHUB_USER_PATH</code> is set.</td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTERHUB_USER_PATH</code></td>
                                        <td>Template for the per-user notebook route served by JupyterHub.</td>
                                        <td>When empty, DSP assumes a single JupyterLab instance and embeds the base URL. Set (for example) to <code>user/{username}/lab</code> in JupyterHub deployments.</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_OAUTH_CLIENT_ID</code></td>
                                        <td>Client identifier issued to JupyterHub.</td>
                                        <td>Matches the record created in <code>dsp_oauth_clients</code>.</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_OAUTH_CLIENT_SECRET</code></td>
                                        <td>Confidential secret shared with JupyterHub.</td>
                                        <td>Store securely (prefer Docker secrets or vault tooling).</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_OAUTH_AUTHORIZE_URL</code></td>
                                        <td>Endpoint JupyterHub uses for the OAuth authorization code flow.</td>
                                        <td>Typically <code>https://portal.example.com/oauth/authorize</code>.</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_OAUTH_TOKEN_URL</code></td>
                                        <td>Token exchange endpoint exposed by DSP.</td>
                                        <td>Typically <code>https://portal.example.com/oauth/token</code>.</td>
                                    </tr>
                                    <tr>
                                        <td><code>DSP_OAUTH_USERINFO_URL</code></td>
                                        <td>Endpoint returning user profile details for JupyterHub.</td>
                                        <td>Typically <code>https://portal.example.com/oauth/userinfo</code>.</td>
                                    </tr>
                                    <tr>
                                        <td><code>JUPYTERHUB_OAUTH_CALLBACK</code></td>
                                        <td>Callback URL the hub advertises to DSP.</td>
                                        <td>Should match the hub’s public URL (e.g., <code>https://hub.example.com/hub/oauth_callback</code>).</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <ul class="mb-0 text-muted">
                            <li>Seeded R scripts live under <code>r_scripts/</code> and appear in the notebook at <code>work/r_scripts</code> for quick demos.</li>
                            <li>When tightening security headers, keep <code>DSP_APP_ORIGINS</code> and <code>DSP_FRAME_ANCESTORS</code> aligned with your published host so the embedded notebook continues to load.</li>
                        </ul>
                        <h3 class="h6 text-uppercase text-muted mt-4 mb-3">Current Runtime Snapshot</h3>
                        <div class="table-responsive mb-3">
                            <table class="table table-bordered align-middle">
                                <thead class="table-light">
                                    <tr>
                                        <th scope="col">Setting</th>
                                        <th scope="col">Value (detected)</th>
                                        <th scope="col">Notes</th>
                                    </tr>
                                </thead>
                                <tbody>
                                    <tr>
                                        <td>Notebook Base URL</td>
                                        <td><code><?= htmlspecialchars($resolvedBaseUrl, ENT_QUOTES, 'UTF-8') ?></code></td>
                                        <td>Derived from <code>JUPYTER_EXTERNAL_URL</code> or the active host/port.</td>
                                    </tr>
                                    <tr>
                                        <td>Published Port</td>
                                        <td><code><?= htmlspecialchars($resolvedPort, ENT_QUOTES, 'UTF-8') ?></code></td>
                                        <td>Matches <code>JUPYTERHUB_PORT</code> (or legacy <code>JUPYTER_PORT</code>) when set, otherwise the compose default.</td>
                                    </tr>
                                    <tr>
                                        <td>Authentication Token</td>
                                        <td><code><?= htmlspecialchars($resolvedToken, ENT_QUOTES, 'UTF-8') ?></code></td>
                                        <td>Leave blank when OAuth is enabled via JupyterHub.</td>
                                    </tr>
                                    <tr>
                                        <td>Workspace Mount</td>
                                        <td><code><?= htmlspecialchars($workspaceBaseMessage, ENT_QUOTES, 'UTF-8') ?></code></td>
                                        <td>Reflects the root folder synced into notebooks for the active account.</td>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                        <h4 class="h6 text-uppercase text-muted mb-2">Active Environment Overrides</h4>
                        <?php if ($activeJupyterOverrides): ?>
                            <ul class="small text-muted mb-0">
                                <?php foreach ($activeJupyterOverrides as $variable => $value): ?>
                                    <li><code><?= htmlspecialchars($variable, ENT_QUOTES, 'UTF-8') ?></code>: <code><?= htmlspecialchars($value, ENT_QUOTES, 'UTF-8') ?></code></li>
                                <?php endforeach; ?>
                            </ul>
                        <?php else: ?>
                            <p class="small text-muted mb-0">No overrides detected; defaults from <code>docker-compose.yml</code> are currently active.</p>
                        <?php endif; ?>
                    </div>
                </div>
            </section>

            <section class="mb-4">
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-secondary">Maintenance Commands</h2>
                        <pre class="bg-light border rounded p-3 mb-0 text-muted"><code># Stop and remove containers, keep database volume
docker-compose down

# Stop containers and remove database volume (fresh start)
docker-compose down -v

# Tail logs from all services
docker-compose logs -f</code></pre>
                    </div>
                </div>
            </section>

            <section>
                <div class="card shadow-sm border-0">
                    <div class="card-body">
                        <h2 class="h4 mb-3 text-danger">Troubleshooting</h2>
                        <ul class="mb-0 text-muted">
                            <li class="mb-2"><strong>Database state stuck?</strong> Remove the <code>mysql_data</code> volume with <code>docker-compose down -v</code> to trigger a fresh import.</li>
                            <li class="mb-2"><strong>Rscript not found?</strong> Rebuild the PHP image (<code>docker-compose build</code>) or set <code>RSCRIPT_PATH</code> to the correct binary.</li>
                            <li class="mb-2"><strong>Port already in use?</strong> Adjust published ports (<code>8081</code>, <code>8082</code>, <code>8888</code>, <code>3307</code>) in <code>docker-compose.yml</code>.</li>
                            <li class="mb-0"><strong>Permission denied on uploads?</strong> Run <code>chmod -R 775 uploads</code> (or update group ownership) on the host machine.</li>
                        </ul>
                    </div>
                </div>
            </section>
        </div>
    </div>

    <div class="modal fade" id="ecosystemDiagramModal" tabindex="-1" aria-labelledby="ecosystemDiagramLabel" aria-hidden="true">
        <div class="modal-dialog modal-xl modal-dialog-centered">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title" id="ecosystemDiagramLabel">NIPH DSP Data Ecosystem</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
                </div>
                <div class="modal-body text-center">
                    <img src="assets/images/niph_dsp_data_ecosystem.png" alt="NIPH DSP data ecosystem expanded view" class="img-fluid rounded border shadow-sm">
                </div>
            </div>
        </div>
    </div>

    <?php include_once __DIR__ . '/includes/footer_admin.php'; ?>
</body>
</html>
