<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>D.S.T.</title>
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css">
    <style>
        :root {
            --app-bg: #f4f6f8;
            --panel-bg: #ffffff;
            --panel-muted: #eef2f5;
            --text: #17202a;
            --muted: #657180;
            --border: #d7dee6;
            --accent: #1d6fd1;
            --accent-strong: #14559f;
            --table-hover: #edf4fb;
            --footer-bg: #eef2f5;
            --danger-bg: #f8d7da;
            --danger-text: #721c24;
            --info-bg: #d9edf7;
            --info-text: #0c5460;
        }

        [data-theme="dark"] {
            --app-bg: #101417;
            --panel-bg: #171d22;
            --panel-muted: #20282f;
            --text: #ecf1f5;
            --muted: #aab7c2;
            --border: #34404a;
            --accent: #71a7ff;
            --accent-strong: #9dc2ff;
            --table-hover: #22303a;
            --footer-bg: #12181d;
            --danger-bg: #3d1d22;
            --danger-text: #ffb7c0;
            --info-bg: #15313a;
            --info-text: #bdeffc;
        }

        html, body {
            min-height: 100%;
        }

        body {
            background: var(--app-bg);
            color: var(--text);
        }

        .app-shell {
            min-height: 100vh;
            display: flex;
            flex-direction: column;
        }

        .app-header {
            background: var(--panel-bg);
            border-bottom: 1px solid var(--border);
            padding: 22px 28px;
            display: flex;
            justify-content: space-between;
            align-items: flex-start;
            gap: 24px;
        }

        .app-kicker {
            color: var(--muted);
            font-size: 13px;
            margin: 0 0 4px;
            text-transform: uppercase;
            letter-spacing: .08em;
        }

        .app-title {
            margin: 0;
            font-size: 28px;
            line-height: 1.2;
        }

        .app-subtitle {
            color: var(--muted);
            margin: 6px 0 0;
            max-width: 820px;
        }

        .header-actions {
            display: flex;
            align-items: center;
            gap: 10px;
            flex-wrap: wrap;
            justify-content: flex-end;
        }

        .version-pill {
            border: 1px solid var(--border);
            border-radius: 6px;
            padding: 7px 10px;
            color: var(--muted);
            background: var(--panel-muted);
            font-size: 13px;
            white-space: nowrap;
        }

        .app-main {
            width: 100%;
            max-width: 1440px;
            margin: 0 auto;
            padding: 24px;
            flex: 1;
        }

        .dst-tabs {
            display: flex;
            flex-wrap: wrap;
            gap: 8px;
            margin-bottom: 16px;
            border-bottom: 1px solid var(--border);
            padding-bottom: 10px;
        }

        .dst-tab-button {
            border: 1px solid var(--border);
            background: var(--panel-bg);
            color: var(--text);
            border-radius: 6px;
            padding: 9px 13px;
            line-height: 1.2;
            cursor: pointer;
        }

        .dst-tab-button.active {
            background: var(--accent);
            color: #ffffff;
            border-color: var(--accent);
        }

        .tab-pane {
            display: none;
            background: var(--panel-bg);
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 20px;
        }

        .tab-pane.active {
            display: block;
        }

        .section-heading {
            margin-bottom: 16px;
        }

        .section-heading h2 {
            font-size: 22px;
            margin: 0 0 4px;
        }

        .section-heading p {
            margin: 0;
            color: var(--muted);
        }

        fieldset {
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 16px;
            margin-bottom: 16px;
        }

        legend {
            width: auto;
            padding: 0 8px;
            font-size: 18px;
            color: var(--text);
        }

        .form-control,
        .custom-select {
            background-color: var(--panel-bg);
            color: var(--text);
            border-color: var(--border);
        }

        .form-control:focus {
            background-color: var(--panel-bg);
            color: var(--text);
            border-color: var(--accent);
            box-shadow: 0 0 0 .2rem rgba(29, 111, 209, .18);
        }

        .form-text,
        .text-muted {
            color: var(--muted) !important;
        }

        .table {
            color: var(--text);
            background: var(--panel-bg);
        }

        .table-bordered,
        .table-bordered td,
        .table-bordered th {
            border-color: var(--border);
        }

        .table thead th {
            background: var(--panel-muted);
            border-color: var(--border);
        }

        .table-hover tbody tr:hover {
            background-color: var(--table-hover);
        }

        pre.border {
            border-color: var(--border) !important;
            background: var(--panel-muted);
            color: var(--text);
        }

        .pagination-controls {
            display: flex;
            justify-content: space-between;
            align-items: center;
            margin-top: 10px;
            gap: 12px;
        }

        #loading-spinner {
            display: none;
        }

        #no-results, #error-message, #schema-message {
            display: none;
            text-align: center;
            margin-top: 20px;
        }

        .alert-info {
            background: var(--info-bg);
            color: var(--info-text);
            border-color: var(--border);
        }

        .alert-danger {
            background: var(--danger-bg);
            color: var(--danger-text);
            border-color: var(--border);
        }

        .license-panel {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
            gap: 16px;
        }

        .template-grid {
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
            gap: 12px;
            margin-bottom: 18px;
        }

        .template-card {
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 14px;
            background: var(--panel-muted);
        }

        .template-card h3 {
            font-size: 16px;
            margin: 0 0 6px;
        }

        .template-card p {
            color: var(--muted);
            margin: 0 0 10px;
            font-size: 14px;
        }

        .license-card {
            border: 1px solid var(--border);
            border-radius: 8px;
            padding: 16px;
            background: var(--panel-muted);
        }

        footer {
            background-color: var(--footer-bg);
            border-top: 1px solid var(--border);
            padding: 18px 0;
        }

        .footer-text {
            font-size: 14px;
            color: var(--muted);
            margin: 0;
        }

        a {
            color: var(--accent);
        }

        a:hover {
            color: var(--accent-strong);
        }

        @media (max-width: 768px) {
            .app-header {
                flex-direction: column;
                padding: 18px;
            }

            .app-main {
                padding: 14px;
            }

            .tab-pane {
                padding: 14px;
            }

            .dst-tab-button {
                flex: 1 1 calc(50% - 8px);
            }
        }
    </style>
</head>
<body>
<div class="app-shell">
    <header class="app-header">
        <div>
            <p class="app-kicker">Viken Data Studio</p>
            <h1 class="app-title">D.S.T. - Databases Searching Tool</h1>
            <p class="app-subtitle">Local-first, read-only SQL Server search with profiles, history, controlled agent access and server-side exports.</p>
        </div>
        <div class="header-actions">
            <span class="version-pill">v1.2.2-templates</span>
            <span class="version-pill">Freeware</span>
            <button type="button" class="btn btn-outline-secondary" id="theme-toggle" onclick="toggleTheme()">
                <span id="theme-label">Dark mode</span>
            </button>
        </div>
    </header>
    <main class="app-main">
        <nav class="dst-tabs" aria-label="D.S.T. workspace tabs">
            <button type="button" class="dst-tab-button active" data-tab="search" onclick="showTab('search')">Search</button>
            <button type="button" class="dst-tab-button" data-tab="results" onclick="showTab('results')">Results</button>
            <button type="button" class="dst-tab-button" data-tab="schema" onclick="showTab('schema')">Schema</button>
            <button type="button" class="dst-tab-button" data-tab="profiles" onclick="showTab('profiles')">Profiles</button>
            <button type="button" class="dst-tab-button" data-tab="agent" onclick="showTab('agent')">Agent Access</button>
            <button type="button" class="dst-tab-button" data-tab="memory" onclick="showTab('memory')">Memory</button>
            <button type="button" class="dst-tab-button" data-tab="license" onclick="showTab('license')">License</button>
        </nav>
        <section class="tab-pane active" id="tab-search">
            <div class="section-heading">
                <h2>Search</h2>
                <p>Use one-time credentials, a saved profile, or an agent-assisted goal while keeping SQL access controlled by the backend.</p>
            </div>
            <div class="template-grid">
                <article class="template-card">
                    <h3>Contact or identity lookup</h3>
                    <p>Search by name, email, phone, username, customer id, employee id, or another person-related value.</p>
                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="applySearchTemplate('contact')">Use template</button>
                </article>
                <article class="template-card">
                    <h3>Reference number lookup</h3>
                    <p>Search exact document ids, ticket ids, order ids, serial numbers, external ids, or other references.</p>
                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="applySearchTemplate('reference')">Use template</button>
                </article>
                <article class="template-card">
                    <h3>Broad contains lookup</h3>
                    <p>Use a controlled contains search across the selected scope when you only know part of a value.</p>
                    <button type="button" class="btn btn-sm btn-outline-primary" onclick="applySearchTemplate('broad')">Use template</button>
                </article>
            </div>
    <form class="mb-0">
        <input type="hidden" name="csrf_token" value="{{ csrf_token }}">
        <fieldset>
            <legend>Connection</legend>
            <div class="form-row">
                <div class="form-group col-md-4">
                    <label for="search-mode">Search Mode</label>
                    <select class="form-control" id="search-mode">
                        <option value="one_time">One-time search</option>
                        <option value="saved_profile" {% if not human_search_profiles %}disabled{% endif %}>Saved profile</option>
                        <option value="agent_assisted" {% if not human_search_profiles %}disabled{% endif %}>Agent-assisted search</option>
                    </select>
                </div>
                <div class="form-group col-md-4">
                    <label for="connection-mode">Connection mode</label>
                    <select class="form-control" id="connection-mode" name="connection_mode">
                        <option value="legacy">Direct credentials</option>
                        <option value="profile" {% if not human_search_profiles %}disabled{% endif %}>Search Profile</option>
                    </select>
                </div>
                <div class="form-group col-md-4" id="profile-search-group" style="display: none;">
                    <label for="search_profile_id">Search Profile</label>
                    <select class="form-control" id="search_profile_id" name="search_profile_id" disabled>
                        <option value="">Select profile</option>
                        {% for profile in human_search_profiles %}
                        <option value="{{ profile.profile_id }}">{{ profile.name }} ({{ profile.profile_id }}){% if not profile.credential_ready %} - not ready{% endif %}</option>
                        {% endfor %}
                    </select>
                </div>
            </div>
            <div class="form-row align-items-end">
                <div class="form-group col-md-4">
                    <label for="workspace_id">Workspace</label>
                    <select class="form-control" id="workspace_id" name="workspace_id">
                        <option value="">No workspace</option>
                    </select>
                </div>
                <div class="form-group col-md-5">
                    <label for="workspace-name">New workspace</label>
                    <input type="text" class="form-control" id="workspace-name" placeholder="Lookup case 2026-05-21">
                </div>
                <div class="form-group col-md-3">
                    <button type="button" class="btn btn-outline-secondary btn-block" onclick="createWorkspace()">Create workspace</button>
                </div>
            </div>
            <div id="legacy-credentials">
                <div class="form-group">
                    <label for="server">Server:</label>
                    <input type="text" class="form-control" id="server" name="server" value="{{ server }}" placeholder="sql-server-host" required>
                </div>
                <div class="form-group">
                    <label for="user">User:</label>
                    <input type="text" class="form-control" id="user" name="user" value="{{ user }}" placeholder="readonly_user" required>
                </div>
                <div class="form-group">
                    <label for="password">Password:</label>
                    <input type="password" class="form-control" id="password" name="password" value="{{ password }}" autocomplete="current-password" required>
                </div>
            </div>
            <div class="form-group">
                <label for="search_value">Search value:</label>
                <input type="text" class="form-control" id="search_value" name="search_value" placeholder="name, email, phone, reference number, external id" required>
            </div>
            <div class="form-group" id="agent-goal-group" style="display: none;">
                <label for="agent-goal">Goal</label>
                <textarea class="form-control" id="agent-goal" rows="2" placeholder="Find all records related to this value across the approved profile scope."></textarea>
            </div>
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="use_percent" name="use_percent" value="1" {% if session.get('use_percent', False) %}checked{% endif %}>
                <label class="form-check-label" for="use_percent">
                    Use '%' signs
                </label>
            </div>      
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="specific_dbs" name="specific_dbs" value="1" {% if session.get('specific_dbs', False) %}checked{% endif %}>
                <label class="form-check-label" for="specific_dbs">
                    Search in specific databases 
                </label>
            </div>
            <div class="form-group" id="db-name-group" style="display: none;">
                <label for="db_name">Databases names:</label>
                <input type="text" class="form-control" id="db_name" name="db_name" value="{{ db_name }}" placeholder="PrimaryDB,ArchiveDB">
            </div>
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="specific_tables" name="specific_tables" value="1" {% if session.get('specific_tables', False) %}checked{% endif %}>
                <label class="form-check-label" for="specific_tables">
                    Search in specific tables 
                </label>
            </div>
            <div class="form-group" id="table-list-group" style="display: none;">
                <label for="table_list">Table names:</label>
                <input type="text" class="form-control" id="table_list" name="table_list" value="{{ table_list }}" placeholder="dbo.Contacts,dbo.Documents,dbo.Records">
                <small class="form-text text-muted">Use TableName or schema.TableName.</small>
            </div>
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="specific_rows" name="specific_rows" value="1" {% if session.get('specific_rows', False) %}checked{% endif %}>
                <label class="form-check-label" for="specific_rows">
                    Search in specific columns
                </label>
            </div>
            <div class="form-group" id="row-list-group" style="display: none;">
                <label for="row_list">Column names:</label>
                <input type="text" class="form-control" id="row_list" name="row_list" value="{{ row_list }}" placeholder="Name,Email,Phone,ReferenceNo,ExternalId">
            </div>
            <div>
                <p>Use "," (comma) to separate names (empty spaces doesn't matter).</p>
            </div>
        </fieldset>
        <button type="button" class="btn btn-outline-secondary" onclick="preflightSearch()">Preflight</button>
        <button type="button" class="btn btn-primary" onclick="performSearch()">Search</button>
        <button type="button" class="btn btn-secondary" id="cancel-btn" onclick="cancelSearch()" disabled>Cancel</button>
        <button type="button" class="btn btn-outline-primary" id="export-page-csv-btn" onclick="exportSearch('csv', 'page')" disabled>Export Page CSV</button>
        <button type="button" class="btn btn-outline-primary" id="export-csv-btn" onclick="exportSearch('csv', 'stored_results')" disabled>Export Stored CSV</button>
        <button type="button" class="btn btn-outline-primary" id="export-jsonl-btn" onclick="exportSearch('jsonl', 'stored_results')" disabled>Export Stored JSONL</button>
    </form>
        </section>
        <section class="tab-pane" id="tab-schema">
            <div class="section-heading">
                <h2>Schema Explorer</h2>
                <p>Browse databases, tables and searchable columns separately from data search. This avoids wildcard-only scans.</p>
            </div>
    <div class="template-grid">
        <article class="template-card">
            <h3>Minimum setup flow</h3>
            <p>Refresh databases, pick one database, show tables, pick one table, then show searchable columns. Copy useful names into a profile allowlist.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="loadSchemaDatabases()">Start with databases</button>
        </article>
        <article class="template-card">
            <h3>Profile scope review</h3>
            <p>In saved profile mode, Schema Explorer shows only allowed profile scope, which is useful before enabling agent access.</p>
            <button type="button" class="btn btn-sm btn-outline-secondary" onclick="showTab('profiles')">Open profiles</button>
        </article>
    </div>
    <div class="form-row align-items-end">
        <div class="form-group col-md-3">
            <button type="button" class="btn btn-outline-secondary btn-block" onclick="loadSchemaDatabases()">Refresh databases</button>
        </div>
        <div class="form-group col-md-3">
            <label for="schema-db-select">Database</label>
            <select class="form-control" id="schema-db-select"></select>
        </div>
        <div class="form-group col-md-3">
            <button type="button" class="btn btn-outline-secondary btn-block" onclick="loadSchemaTables()">Show tables</button>
        </div>
        <div class="form-group col-md-3">
            <label for="schema-table-select">Table</label>
            <select class="form-control" id="schema-table-select"></select>
        </div>
    </div>
    <button type="button" class="btn btn-outline-secondary" onclick="loadSchemaColumns()">Show searchable columns</button>
    <div id="schema-message" class="alert alert-info"></div>
    <br>
    <table class="table table-sm table-bordered" id="schema-results-table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Type</th>
                <th>Searchable</th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>
        </section>
        <section class="tab-pane" id="tab-profiles">
            <div class="section-heading">
                <h2>Search Profiles</h2>
                <p>Store reusable read-only search scope and credential references for human and approved agent workflows.</p>
            </div>
    <div class="template-grid">
        <article class="template-card">
            <h3>General lookup profile</h3>
            <p>Good default for searching common text/id fields in a primary and archive database.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyProfileTemplate('general')">Use template</button>
        </article>
        <article class="template-card">
            <h3>Support case profile</h3>
            <p>Narrower profile for support-style lookups by contact, ticket, serial, or external reference.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyProfileTemplate('support')">Use template</button>
        </article>
        <article class="template-card">
            <h3>Audit review profile</h3>
            <p>Metadata-heavy profile with masked agent results and exports disabled by default.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyProfileTemplate('audit')">Use template</button>
        </article>
    </div>
    <p id="profile-status"></p>
    <div class="form-row align-items-end">
        <div class="form-group col-md-3">
            <label for="profile-id">Profile ID</label>
            <input type="text" class="form-control" id="profile-id" placeholder="main_lookup_readonly">
        </div>
        <div class="form-group col-md-3">
            <label for="profile-name">Name</label>
            <input type="text" class="form-control" id="profile-name" placeholder="Main Data Lookup - Read Only">
        </div>
        <div class="form-group col-md-3">
            <label for="profile-server">SQL Server</label>
            <input type="text" class="form-control" id="profile-server" placeholder="sql-host">
        </div>
        <div class="form-group col-md-3">
            <label for="profile-user">SQL User</label>
            <input type="text" class="form-control" id="profile-user" placeholder="readonly_user">
        </div>
    </div>
    <div class="form-row align-items-end">
        <div class="form-group col-md-3">
            <label for="profile-auth-mode">Credential source</label>
            <select class="form-control" id="profile-auth-mode">
                <option value="password_env">password_env</option>
                <option value="windows_credential">windows_credential</option>
                <option value="local_vault">local_vault</option>
            </select>
        </div>
        <div class="form-group col-md-3">
            <label for="profile-password-env">Password env</label>
            <input type="text" class="form-control" id="profile-password-env" placeholder="DST_SQL_LOOKUP_PASSWORD">
        </div>
        <div class="form-group col-md-3">
            <label for="profile-credential-ref">Credential ref</label>
            <input type="text" class="form-control" id="profile-credential-ref" placeholder="DST/SQL/main_lookup_readonly">
        </div>
        <div class="form-group col-md-3">
            <label for="profile-credential-password">Credential password</label>
            <input type="password" class="form-control" id="profile-credential-password" autocomplete="new-password">
        </div>
    </div>
    <div class="form-row align-items-end">
        <div class="form-group col-md-4">
            <label for="profile-databases">Allowed databases</label>
            <input type="text" class="form-control" id="profile-databases" placeholder="PrimaryDB,ArchiveDB">
        </div>
        <div class="form-group col-md-4">
            <label for="profile-tables">Allowed tables</label>
            <input type="text" class="form-control" id="profile-tables" placeholder="dbo.Customers,dbo.Invoices">
        </div>
        <div class="form-group col-md-4">
            <label for="profile-columns">Allowed columns</label>
            <input type="text" class="form-control" id="profile-columns" placeholder="Name,Email,InvoiceNo">
        </div>
    </div>
    <div class="form-row align-items-end">
        <div class="form-group col-md-2">
            <label for="profile-max-preview">Preview rows</label>
            <input type="number" class="form-control" id="profile-max-preview" min="1" value="500">
        </div>
        <div class="form-group col-md-2">
            <label for="profile-max-export">Export rows</label>
            <input type="number" class="form-control" id="profile-max-export" min="1" value="50000">
        </div>
        <div class="form-group col-md-2">
            <label for="profile-max-page">Max page</label>
            <input type="number" class="form-control" id="profile-max-page" min="1" value="500">
        </div>
        <div class="form-group col-md-2">
            <label for="profile-masking">Agent visibility</label>
            <select class="form-control" id="profile-masking">
                <option value="preview">preview</option>
                <option value="masked">masked</option>
                <option value="metadata_only">metadata_only</option>
                <option value="full_value">full_value</option>
            </select>
        </div>
        <div class="form-group col-md-2">
            <label for="profile-audit-query">Audit query</label>
            <select class="form-control" id="profile-audit-query">
                <option value="hash">hash</option>
                <option value="masked">masked</option>
                <option value="full">full</option>
                <option value="none">none</option>
            </select>
        </div>
        <div class="form-group col-md-2">
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="profile-export-allowed">
                <label class="form-check-label" for="profile-export-allowed">Agent export</label>
            </div>
        </div>
        <div class="form-group col-md-2">
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="profile-agent-enabled" checked>
                <label class="form-check-label" for="profile-agent-enabled">Agent access</label>
            </div>
        </div>
    </div>
    <div class="form-row align-items-end">
        <div class="form-group col-md-2">
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="profile-history-enabled" checked>
                <label class="form-check-label" for="profile-history-enabled">History</label>
            </div>
        </div>
        <div class="form-group col-md-3">
            <label for="profile-history-detail">History detail</label>
            <select class="form-control" id="profile-history-detail">
                <option value="metadata_only">metadata_only</option>
                <option value="summary_only">summary_only</option>
                <option value="preview_rows">preview_rows</option>
                <option value="full_rows">full_rows</option>
            </select>
        </div>
        <div class="form-group col-md-2">
            <label for="profile-history-retention">History days</label>
            <input type="number" class="form-control" id="profile-history-retention" min="0" value="30">
        </div>
    </div>
    <button type="button" class="btn btn-outline-secondary" onclick="loadSearchProfiles()">Refresh profiles</button>
    <button type="button" class="btn btn-outline-primary" onclick="saveSearchProfile()">Save profile</button>
    <button type="button" class="btn btn-outline-secondary" onclick="saveWindowsCredential()">Save Windows credential</button>
    <button type="button" class="btn btn-outline-secondary" onclick="saveLocalVaultCredential()">Save local vault credential</button>
    <button type="button" class="btn btn-outline-secondary" onclick="checkSearchProfileStatus()">Check readiness</button>
    <button type="button" class="btn btn-outline-secondary" onclick="testSearchProfile()">Test connection</button>
    <button type="button" class="btn btn-outline-danger" onclick="deleteSearchProfile()">Delete profile</button>
    <pre id="profile-output" class="border p-2 mt-3" style="display: none; white-space: pre-wrap;"></pre>
        </section>
        <section class="tab-pane" id="tab-agent">
            <div class="section-heading">
                <h2>Agent Access</h2>
                <p>Create scoped tokens, review API state and audit agent activity without exposing credentials.</p>
            </div>
    <div class="template-grid">
        <article class="template-card">
            <h3>Local assistant token</h3>
            <p>Preview-only default for a local AI assistant using one approved profile.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyAgentTemplate('local')">Use template</button>
        </article>
        <article class="template-card">
            <h3>Support workflow token</h3>
            <p>Masked results, no export, short expiry. Good default for controlled support workflows.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyAgentTemplate('support')">Use template</button>
        </article>
        <article class="template-card">
            <h3>Audit review token</h3>
            <p>Metadata-only results and no export. Use when the agent should only see where matches exist.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyAgentTemplate('audit')">Use template</button>
        </article>
    </div>
    <p id="agent-status"></p>
    <div class="form-row align-items-end">
        <div class="form-group col-md-3">
            <label for="agent-token-name">Token name</label>
            <input type="text" class="form-control" id="agent-token-name" placeholder="Local Search Assistant">
        </div>
        <div class="form-group col-md-3">
            <label for="agent-profile-ids">Profile IDs</label>
            <input type="text" class="form-control" id="agent-profile-ids" placeholder="main_lookup_readonly">
        </div>
        <div class="form-group col-md-2">
            <label for="agent-expires-days">Expires days</label>
            <input type="number" class="form-control" id="agent-expires-days" min="1" placeholder="30">
        </div>
        <div class="form-group col-md-2">
            <label for="agent-visibility">Visibility</label>
            <select class="form-control" id="agent-visibility">
                <option value="preview">preview</option>
                <option value="masked">masked</option>
                <option value="metadata_only">metadata_only</option>
                <option value="full_value">full_value</option>
            </select>
        </div>
        <div class="form-group col-md-2">
            <div class="form-check">
                <input class="form-check-input" type="checkbox" id="agent-export-allowed">
                <label class="form-check-label" for="agent-export-allowed">Export</label>
            </div>
        </div>
    </div>
    <button type="button" class="btn btn-outline-secondary" onclick="loadAgentSettings()">Refresh agent settings</button>
    <button type="button" class="btn btn-outline-primary" onclick="createAgentToken()">Create token</button>
    <button type="button" class="btn btn-outline-danger" onclick="disableAgentApi()">Disable Agent API now</button>
    <button type="button" class="btn btn-outline-secondary" onclick="loadAuditLog()">View audit log</button>
    <button type="button" class="btn btn-outline-secondary" onclick="exportAuditLog('jsonl')">Export audit JSONL</button>
    <button type="button" class="btn btn-outline-secondary" onclick="exportAuditLog('csv')">Export audit CSV</button>
    <pre id="agent-output" class="border p-2 mt-3" style="display: none; white-space: pre-wrap;"></pre>
        </section>
        <section class="tab-pane" id="tab-memory">
            <div class="section-heading">
                <h2>Search Memory</h2>
                <p>Review search history, workspaces and saved searches with retention controlled by profile settings.</p>
            </div>
    <div class="template-grid">
        <article class="template-card">
            <h3>Lookup case workspace</h3>
            <p>Use for a single investigation across multiple values and searches.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyWorkspaceTemplate('lookup')">Use template</button>
        </article>
        <article class="template-card">
            <h3>Support investigation workspace</h3>
            <p>Use for troubleshooting a ticket, user issue, device, record, or external reference.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyWorkspaceTemplate('support')">Use template</button>
        </article>
        <article class="template-card">
            <h3>Data review workspace</h3>
            <p>Use for audit, migration, reconciliation, or quality checks where history matters.</p>
            <button type="button" class="btn btn-sm btn-outline-primary" onclick="applyWorkspaceTemplate('review')">Use template</button>
        </article>
    </div>
    <div class="form-row align-items-end">
        <div class="form-group col-md-3">
            <label for="history-profile-filter">Profile</label>
            <select class="form-control" id="history-profile-filter">
                <option value="">All profiles</option>
                {% for profile in human_search_profiles %}
                <option value="{{ profile.profile_id }}">{{ profile.name }}</option>
                {% endfor %}
            </select>
        </div>
        <div class="form-group col-md-3">
            <label for="history-workspace-filter">Workspace</label>
            <select class="form-control" id="history-workspace-filter">
                <option value="">All workspaces</option>
            </select>
        </div>
        <div class="form-group col-md-2">
            <label for="history-actor-filter">Actor</label>
            <select class="form-control" id="history-actor-filter">
                <option value="">All</option>
                <option value="human">human</option>
                <option value="agent">agent</option>
            </select>
        </div>
        <div class="form-group col-md-4">
            <button type="button" class="btn btn-outline-secondary" onclick="loadHistory()">Refresh history</button>
            <button type="button" class="btn btn-outline-secondary" onclick="saveCurrentSearch()">Save current</button>
            <button type="button" class="btn btn-outline-secondary" onclick="loadSavedSearches()">Saved searches</button>
        </div>
    </div>
    <div id="memory-message" class="alert alert-info" style="display: none;"></div>
    <table class="table table-sm table-bordered" id="history-table">
        <thead>
            <tr>
                <th>Created</th>
                <th>Profile</th>
                <th>Actor</th>
                <th>Query</th>
                <th>Status</th>
                <th>Results</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>
    <table class="table table-sm table-bordered" id="saved-searches-table">
        <thead>
            <tr>
                <th>Name</th>
                <th>Profile</th>
                <th>Query</th>
                <th>Mode</th>
                <th>Actions</th>
            </tr>
        </thead>
        <tbody></tbody>
    </table>
    <pre id="history-output" class="border p-2 mt-3" style="display: none; white-space: pre-wrap;"></pre>
        </section>
        <section class="tab-pane" id="tab-results">
            <div class="section-heading">
                <h2>Results</h2>
                <p>Only the active server-side page is rendered in the browser. Use export actions for larger result sets.</p>
            </div>
    <p id="search-summary"></p>
    <div id="loading-spinner" class="text-center">
        <div class="spinner-border" role="status">
            <span class="sr-only">Loading...</span>
        </div>
    </div>
    <br>
    <table class="table table-bordered table-hover" id="results-table">
        <thead>
            <tr>
                <th>Database</th>
                <th>Table</th>
                <th>Column Name</th>
                <th>Value</th>
                <th>Rows Count</th>
                <th>Type</th>
            </tr>
        </thead>
        <tbody>
        </tbody>
    </table>
    <br>
    <div class="pagination-controls">
        <button onclick="prevPage()" id="prev-btn" class="btn btn-secondary">Previous</button>
        <span id="page-info">Page 1 of 1</span>
        <button onclick="nextPage()" id="next-btn" class="btn btn-secondary">Next</button>
    </div>
    <div id="no-results" class="alert alert-info">No results found for the search term.</div>
    <div id="error-message" class="alert alert-danger">An error occurred. Please try again later.</div>
        </section>
        <section class="tab-pane" id="tab-license">
            <div class="section-heading">
                <h2>License & Support</h2>
                <p>D.S.T. is freeware from Viken Data Studio. Use it with your own operational and data protection controls.</p>
            </div>
            <div class="license-panel">
                <div class="license-card">
                    <h3>Freeware</h3>
                    <p>D.S.T. can be used free of charge for personal, internal and company workflows. The license does not include warranty, liability, or a guarantee of suitability for a specific environment.</p>
                </div>
                <div class="license-card">
                    <h3>No Liability</h3>
                    <p>You are responsible for validating access rights, database permissions, result handling, backups, and compliance before using the tool on real systems.</p>
                </div>
                <div class="license-card">
                    <h3>Commercial Help</h3>
                    <p>Viken Data Studio can help with training, configuration, and implementation into internal company workflows. Pricing is individual. Contact: <a href="mailto:support@vikendata.com">support@vikendata.com</a>.</p>
                </div>
            </div>
        </section>
    </main>
</div>
<br>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script>
    let currentPage = 1;
    let totalPages = 1;
    let currentSearchId = null;
    let nextCursor = null;
    let previousCursor = null;
    let activeSearchValue = '';
    let currentSearchRequest = null;
    let searchPollTimer = null;

    function setTheme(theme) {
        const selectedTheme = theme === 'dark' ? 'dark' : 'light';
        document.documentElement.setAttribute('data-theme', selectedTheme);
        localStorage.setItem('dst-theme', selectedTheme);
        $('#theme-label').text(selectedTheme === 'dark' ? 'Light mode' : 'Dark mode');
    }

    function toggleTheme() {
        const currentTheme = document.documentElement.getAttribute('data-theme') || 'light';
        setTheme(currentTheme === 'dark' ? 'light' : 'dark');
    }

    function initTheme() {
        const storedTheme = localStorage.getItem('dst-theme');
        const preferredTheme = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light';
        setTheme(storedTheme || preferredTheme);
    }

    function showTab(tabName) {
        const safeTabName = tabName || 'search';
        $('.dst-tab-button').removeClass('active');
        $(`.dst-tab-button[data-tab="${safeTabName}"]`).addClass('active');
        $('.tab-pane').removeClass('active');
        $(`#tab-${safeTabName}`).addClass('active');
        localStorage.setItem('dst-active-tab', safeTabName);
    }

    function initTabs() {
        const storedTab = localStorage.getItem('dst-active-tab') || 'search';
        if ($(`#tab-${storedTab}`).length) {
            showTab(storedTab);
        } else {
            showTab('search');
        }
    }

    function isoDate() {
        return new Date().toISOString().slice(0, 10);
    }

    function applySearchTemplate(templateName) {
        const templates = {
            contact: {
                value: 'name@example.com',
                usePercent: false,
                tables: 'dbo.Contacts,dbo.Users,dbo.Accounts',
                columns: 'Name,Email,Phone,Username,ExternalId',
                goal: 'Find records related to a person, account, email, phone number, username, or external id.'
            },
            reference: {
                value: 'REF-2026-001',
                usePercent: false,
                tables: 'dbo.Documents,dbo.Records,dbo.Events',
                columns: 'ReferenceNo,DocumentNo,TicketNo,ExternalId,SerialNo',
                goal: 'Find an exact reference, document number, ticket id, serial number, or external id.'
            },
            broad: {
                value: 'search fragment',
                usePercent: true,
                tables: '',
                columns: 'Name,Description,Email,Phone,ReferenceNo,ExternalId',
                goal: 'Search for a partial value across the approved scope and refine by table or column if the result set is too large.'
            }
        };
        const template = templates[templateName] || templates.contact;
        $('#search_value').val(template.value);
        $('#use_percent').prop('checked', template.usePercent);
        $('#agent-goal').val(template.goal);
        $('#specific_tables').prop('checked', Boolean(template.tables));
        $('#table_list').val(template.tables);
        $('#specific_rows').prop('checked', Boolean(template.columns));
        $('#row_list').val(template.columns);
        toggleTableListGroup();
        toggleRowListGroup();
        showTab('search');
    }

    function applyProfileTemplate(templateName) {
        const templates = {
            general: {
                id: 'main_lookup_readonly',
                name: 'Main Data Lookup - Read Only',
                server: 'sql-server-host',
                user: 'readonly_user',
                authMode: 'local_vault',
                passwordEnv: 'DST_SQL_LOOKUP_PASSWORD',
                credentialRef: 'DST/SQL/main_lookup_readonly',
                databases: 'PrimaryDB,ArchiveDB',
                tables: 'dbo.Contacts,dbo.Documents,dbo.Records',
                columns: 'Name,Email,Phone,ReferenceNo,ExternalId,Description',
                visibility: 'preview',
                historyDetail: 'summary_only',
                retention: 30,
                exportAllowed: false
            },
            support: {
                id: 'support_lookup_readonly',
                name: 'Support Lookup - Read Only',
                server: 'sql-server-host',
                user: 'readonly_user',
                authMode: 'local_vault',
                passwordEnv: 'DST_SQL_SUPPORT_PASSWORD',
                credentialRef: 'DST/SQL/support_lookup_readonly',
                databases: 'PrimaryDB',
                tables: 'dbo.Contacts,dbo.Tickets,dbo.Devices,dbo.Events',
                columns: 'Name,Email,Phone,TicketNo,SerialNo,ExternalId',
                visibility: 'masked',
                historyDetail: 'summary_only',
                retention: 7,
                exportAllowed: false
            },
            audit: {
                id: 'audit_review_readonly',
                name: 'Audit Review - Read Only',
                server: 'sql-server-host',
                user: 'readonly_user',
                authMode: 'local_vault',
                passwordEnv: 'DST_SQL_AUDIT_PASSWORD',
                credentialRef: 'DST/SQL/audit_review_readonly',
                databases: 'PrimaryDB,ArchiveDB',
                tables: 'dbo.AuditLog,dbo.Events,dbo.Records',
                columns: 'Actor,Action,ReferenceNo,ExternalId,CreatedAt,Description',
                visibility: 'metadata_only',
                historyDetail: 'metadata_only',
                retention: 30,
                exportAllowed: false
            }
        };
        const template = templates[templateName] || templates.general;
        $('#profile-id').val(template.id);
        $('#profile-name').val(template.name);
        $('#profile-server').val(template.server);
        $('#profile-user').val(template.user);
        $('#profile-auth-mode').val(template.authMode);
        $('#profile-password-env').val(template.passwordEnv);
        $('#profile-credential-ref').val(template.credentialRef);
        $('#profile-databases').val(template.databases);
        $('#profile-tables').val(template.tables);
        $('#profile-columns').val(template.columns);
        $('#profile-max-preview').val(500);
        $('#profile-max-export').val(50000);
        $('#profile-max-page').val(500);
        $('#profile-masking').val(template.visibility);
        $('#profile-audit-query').val('hash');
        $('#profile-export-allowed').prop('checked', template.exportAllowed);
        $('#profile-agent-enabled').prop('checked', true);
        $('#profile-history-enabled').prop('checked', true);
        $('#profile-history-detail').val(template.historyDetail);
        $('#profile-history-retention').val(template.retention);
        $('#agent-profile-ids').val(template.id);
        showTab('profiles');
    }

    function applyAgentTemplate(templateName) {
        const profileId = $('#profile-id').val() || 'main_lookup_readonly';
        const templates = {
            local: {
                name: 'Local Search Assistant',
                days: 30,
                visibility: 'preview',
                exportAllowed: false
            },
            support: {
                name: 'Support Workflow Assistant',
                days: 7,
                visibility: 'masked',
                exportAllowed: false
            },
            audit: {
                name: 'Audit Review Assistant',
                days: 14,
                visibility: 'metadata_only',
                exportAllowed: false
            }
        };
        const template = templates[templateName] || templates.local;
        $('#agent-token-name').val(template.name);
        $('#agent-profile-ids').val(profileId);
        $('#agent-expires-days').val(template.days);
        $('#agent-visibility').val(template.visibility);
        $('#agent-export-allowed').prop('checked', template.exportAllowed);
        showTab('agent');
    }

    function applyWorkspaceTemplate(templateName) {
        const templates = {
            lookup: `Lookup case ${isoDate()}`,
            support: `Support investigation ${isoDate()}`,
            review: `Data review ${isoDate()}`
        };
        $('#workspace-name').val(templates[templateName] || templates.lookup);
        showTab('search');
    }

    $(document).ready(function() {
        initTheme();
        initTabs();
        // Initial check when the page loads
        toggleConnectionMode();
        toggleSearchMode();
        toggleDbNameGroup();
        toggleTableListGroup();
        toggleRowListGroup();
        loadWorkspaces();
        loadHistory();
        loadSavedSearches();

        $('#connection-mode').change(function() {
            toggleConnectionMode();
        });

        $('#search-mode').change(function() {
            toggleSearchMode();
        });

        // Add event listener to the "Search in specific databases" checkbox
        $('#specific_dbs').change(function() {
            toggleDbNameGroup();
        });

        // Add event listener to the "Search in specific tables" checkbox
        $('#specific_tables').change(function() {
            toggleTableListGroup();
        });

        // Add event listener to the "Search in specific columns" checkbox
        $('#specific_rows').change(function() {
            toggleRowListGroup();
        });
    });

    function toggleConnectionMode() {
        const profileMode = $('#connection-mode').val() === 'profile';
        $('#profile-search-group').toggle(profileMode);
        $('#search_profile_id').prop('disabled', !profileMode);
        $('#legacy-credentials').toggle(!profileMode);
        $('#server, #user, #password')
            .prop('disabled', profileMode)
            .prop('required', !profileMode);
    }

    function toggleSearchMode() {
        const mode = $('#search-mode').val();
        if (mode === 'one_time') {
            $('#connection-mode').val('legacy');
        } else {
            $('#connection-mode').val('profile');
        }
        $('#connection-mode').prop('disabled', mode !== 'one_time');
        $('#agent-goal-group').toggle(mode === 'agent_assisted');
        toggleConnectionMode();
    }

    function toggleDbNameGroup() {
        if ($('#specific_dbs').is(':checked')) {
            $('#db-name-group').show();
        } else {
            $('#db-name-group').hide();
        }
    }

    function toggleTableListGroup() {
        if ($('#specific_tables').is(':checked')) {
            $('#table-list-group').show();
        } else {
            $('#table-list-group').hide();
        }
    }

    function toggleRowListGroup() {
        if ($('#specific_rows').is(':checked')) {
            $('#row-list-group').show();
        } else {
            $('#row-list-group').hide();
        }
    }

    function formDataWith(extraFields) {
        const data = $('form').serializeArray();
        Object.keys(extraFields || {}).forEach(key => {
            data.push({ name: key, value: extraFields[key] });
        });
        return $.param(data);
    }

    function csrfHeaders() {
        return { 'X-CSRF-Token': $('input[name="csrf_token"]').val() };
    }

    function showSchemaMessage(message, type = 'info') {
        $('#schema-message')
            .removeClass('alert-info alert-danger')
            .addClass(type === 'danger' ? 'alert-danger' : 'alert-info')
            .text(message)
            .show();
    }

    function renderSchemaRows(rows) {
        const tableBody = $('#schema-results-table tbody');
        tableBody.empty();
        rows.forEach(row => {
            const tr = $('<tr>');
            tr.append($('<td>').text(row.name));
            tr.append($('<td>').text(row.type || ''));
            tr.append($('<td>').text(row.searchable || ''));
            tableBody.append(tr);
        });
    }

    function loadSchemaDatabases() {
        $('#error-message').hide();
        showSchemaMessage('Loading databases...');
        $.ajax({
            type: 'POST',
            url: '/schema/databases',
            data: formDataWith({}),
            dataType: 'json',
            success: function(data) {
                if (data.error) {
                    showSchemaMessage(data.error, 'danger');
                    return;
                }
                const select = $('#schema-db-select');
                select.empty();
                (data.databases || []).forEach(name => {
                    select.append($('<option>').val(name).text(name));
                });
                $('#schema-table-select').empty();
                renderSchemaRows((data.databases || []).map(name => ({ name, type: 'database', searchable: '' })));
                showSchemaMessage(`Loaded ${data.returned_count || 0} databases.`);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Schema request failed.';
                showSchemaMessage(message, 'danger');
            }
        });
    }

    function loadSchemaTables() {
        const database = $('#schema-db-select').val();
        if (!database) {
            showSchemaMessage('Select a database first.', 'danger');
            return;
        }
        showSchemaMessage('Loading tables...');
        $.ajax({
            type: 'POST',
            url: '/schema/tables',
            data: formDataWith({ database }),
            dataType: 'json',
            success: function(data) {
                if (data.error) {
                    showSchemaMessage(data.error, 'danger');
                    return;
                }
                const select = $('#schema-table-select');
                select.empty();
                (data.tables || []).forEach(table => {
                    select.append($('<option>').val(table.name).text(table.name));
                });
                renderSchemaRows((data.tables || []).map(table => ({ name: table.name, type: 'table', searchable: '' })));
                showSchemaMessage(`Loaded ${data.returned_count || 0} tables.`);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Schema request failed.';
                showSchemaMessage(message, 'danger');
            }
        });
    }

    function loadSchemaColumns() {
        const database = $('#schema-db-select').val();
        const table = $('#schema-table-select').val();
        if (!database || !table) {
            showSchemaMessage('Select a database and table first.', 'danger');
            return;
        }
        showSchemaMessage('Loading columns...');
        $.ajax({
            type: 'POST',
            url: '/schema/columns',
            data: formDataWith({ database, table }),
            dataType: 'json',
            success: function(data) {
                if (data.error) {
                    showSchemaMessage(data.error, 'danger');
                    return;
                }
                renderSchemaRows((data.columns || []).map(column => ({
                    name: column.name,
                    type: column.data_type,
                    searchable: column.searchable ? 'yes' : 'no'
                })));
                showSchemaMessage(`Loaded ${data.returned_count || 0} columns from ${data.table}.`);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Schema request failed.';
                showSchemaMessage(message, 'danger');
            }
        });
    }

    function showProfileOutput(value) {
        const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
        $('#profile-output').text(text).show();
    }

    function fillProfileForm(profile) {
        $('#profile-id').val(profile.profile_id || '');
        $('#profile-name').val(profile.name || '');
        $('#profile-server').val(profile.server || '');
        $('#profile-user').val(profile.user || '');
        $('#profile-auth-mode').val(profile.auth_mode || 'password_env');
        $('#profile-password-env').val(profile.password_env || '');
        $('#profile-credential-ref').val(profile.credential_ref || '');
        $('#profile-credential-password').val('');
        $('#profile-databases').val((profile.allowed_databases || []).join(','));
        $('#profile-tables').val((profile.allowed_tables || []).join(','));
        $('#profile-columns').val((profile.allowed_columns || []).join(','));
        $('#profile-max-preview').val(profile.max_preview_rows || 500);
        $('#profile-max-export').val(profile.max_export_rows || 50000);
        $('#profile-max-page').val(profile.max_page_size || 500);
        $('#profile-masking').val(profile.masking_mode || 'preview');
        $('#profile-audit-query').val(profile.audit_query_mode || 'hash');
        $('#profile-export-allowed').prop('checked', Boolean(profile.allow_agent_export));
        $('#profile-agent-enabled').prop('checked', profile.agent_enabled !== false);
        $('#profile-history-enabled').prop('checked', profile.history_enabled !== false);
        $('#profile-history-detail').val(profile.history_detail_mode || 'summary_only');
        $('#profile-history-retention').val(profile.history_retention_days || 30);
    }

    function profileOptionLabel(profile) {
        const name = profile.name || profile.profile_id || '';
        const ready = profile.credential_ready === false ? ' - not ready' : '';
        return `${name} (${profile.profile_id})${ready}`;
    }

    function syncHumanProfileSelect(profiles) {
        const select = $('#search_profile_id');
        const selected = select.val();
        const historyProfile = $('#history-profile-filter').val();
        select.empty().append($('<option>').val('').text('Select profile'));
        $('#history-profile-filter').empty().append($('<option>').val('').text('All profiles'));
        (profiles || []).forEach(profile => {
            select.append($('<option>').val(profile.profile_id).text(profileOptionLabel(profile)));
            $('#history-profile-filter').append($('<option>').val(profile.profile_id).text(profile.name || profile.profile_id));
        });
        if (selected && (profiles || []).some(profile => profile.profile_id === selected)) {
            select.val(selected);
        }
        if (historyProfile && (profiles || []).some(profile => profile.profile_id === historyProfile)) {
            $('#history-profile-filter').val(historyProfile);
        }
        $('#connection-mode option[value="profile"]').prop('disabled', (profiles || []).length === 0);
        $('#search-mode option[value="saved_profile"], #search-mode option[value="agent_assisted"]').prop('disabled', (profiles || []).length === 0);
        if ((profiles || []).length === 0 && $('#connection-mode').val() === 'profile') {
            $('#connection-mode').val('legacy');
        }
        if ((profiles || []).length === 0 && $('#search-mode').val() !== 'one_time') {
            $('#search-mode').val('one_time');
        }
        toggleSearchMode();
        toggleConnectionMode();
    }

    function upsertHumanProfileOption(profile) {
        if (!profile || !profile.profile_id) {
            return;
        }
        const select = $('#search_profile_id');
        const existing = select.find(`option[value="${profile.profile_id}"]`);
        if (existing.length) {
            existing.text(profileOptionLabel(profile));
        } else {
            select.append($('<option>').val(profile.profile_id).text(profileOptionLabel(profile)));
        }
        $('#connection-mode option[value="profile"]').prop('disabled', false);
        select.val(profile.profile_id);
        toggleConnectionMode();
    }

    function loadSearchProfiles() {
        $.ajax({
            type: 'GET',
            url: '/settings/profiles',
            dataType: 'json',
            success: function(data) {
                const profiles = data.profiles || [];
                $('#profile-status').text(`Profiles: ${profiles.length}`);
                if (profiles.length > 0) {
                    fillProfileForm(profiles[0]);
                }
                syncHumanProfileSelect(profiles);
                showProfileOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Profile settings request failed.';
                showProfileOutput(message);
            }
        });
    }

    function saveSearchProfile() {
        const profileId = $('#profile-id').val();
        const payload = {
            profile_id: profileId,
            name: $('#profile-name').val(),
            server: $('#profile-server').val(),
            user: $('#profile-user').val(),
            auth_mode: $('#profile-auth-mode').val(),
            password_env: $('#profile-password-env').val(),
            credential_ref: $('#profile-credential-ref').val(),
            allowed_databases: $('#profile-databases').val(),
            allowed_tables: $('#profile-tables').val(),
            allowed_columns: $('#profile-columns').val(),
            max_preview_rows: $('#profile-max-preview').val(),
            max_export_rows: $('#profile-max-export').val(),
            max_page_size: $('#profile-max-page').val(),
            masking_mode: $('#profile-masking').val(),
            audit_query_mode: $('#profile-audit-query').val(),
            allow_agent_export: $('#profile-export-allowed').is(':checked'),
            agent_enabled: $('#profile-agent-enabled').is(':checked'),
            history_enabled: $('#profile-history-enabled').is(':checked'),
            history_detail_mode: $('#profile-history-detail').val(),
            history_retention_days: $('#profile-history-retention').val()
        };

        $.ajax({
            type: 'POST',
            url: '/settings/profiles',
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify(payload),
            dataType: 'json',
            success: function(data) {
                $('#profile-status').text(`Profile ${profileId} saved.`);
                if (profileId) {
                    $('#agent-profile-ids').val(profileId);
                }
                upsertHumanProfileOption(data.profile);
                showProfileOutput(data);
                loadAgentSettings();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Profile save failed.';
                showProfileOutput(message);
            }
        });
    }

    function saveWindowsCredential() {
        const credentialRef = $('#profile-credential-ref').val();
        const username = $('#profile-user').val();
        const password = $('#profile-credential-password').val();
        if (!credentialRef || !username || !password) {
            showProfileOutput('Credential ref, SQL user, and credential password are required.');
            return;
        }

        $.ajax({
            type: 'POST',
            url: '/settings/credentials/windows',
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify({
                credential_ref: credentialRef,
                username: username,
                password: password
            }),
            dataType: 'json',
            success: function(data) {
                $('#profile-status').text('Windows credential saved.');
                $('#profile-credential-password').val('');
                showProfileOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Windows credential save failed.';
                showProfileOutput(message);
            }
        });
    }

    function saveLocalVaultCredential() {
        const credentialRef = $('#profile-credential-ref').val();
        const username = $('#profile-user').val();
        const password = $('#profile-credential-password').val();
        if (!credentialRef || !username || !password) {
            showProfileOutput('Credential ref, SQL user, and credential password are required.');
            return;
        }

        $.ajax({
            type: 'POST',
            url: '/settings/credentials/vault',
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify({
                credential_ref: credentialRef,
                username: username,
                password: password
            }),
            dataType: 'json',
            success: function(data) {
                $('#profile-status').text('Local vault credential saved.');
                $('#profile-credential-password').val('');
                showProfileOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Local vault save failed.';
                showProfileOutput(message);
            }
        });
    }

    function deleteSearchProfile() {
        const profileId = $('#profile-id').val();
        if (!profileId) {
            showProfileOutput('Profile ID is required.');
            return;
        }

        $.ajax({
            type: 'POST',
            url: `/settings/profiles/${profileId}/delete`,
            headers: csrfHeaders(),
            dataType: 'json',
            success: function(data) {
                $('#profile-status').text(`Profile ${profileId} deleted.`);
                $(`#search_profile_id option[value="${profileId}"]`).remove();
                if ($('#search_profile_id option').length <= 1) {
                    $('#connection-mode').val('legacy');
                    $('#connection-mode option[value="profile"]').prop('disabled', true);
                }
                toggleConnectionMode();
                showProfileOutput(data);
                loadSearchProfiles();
                loadAgentSettings();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Profile delete failed.';
                showProfileOutput(message);
            }
        });
    }

    function checkSearchProfileStatus() {
        const profileId = $('#profile-id').val();
        if (!profileId) {
            showProfileOutput('Profile ID is required.');
            return;
        }

        $.ajax({
            type: 'GET',
            url: `/settings/profiles/${profileId}/status`,
            dataType: 'json',
            success: function(data) {
                $('#profile-status').text(`Profile ${profileId}: ${data.status}.`);
                showProfileOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Profile readiness check failed.';
                showProfileOutput(message);
            }
        });
    }

    function testSearchProfile() {
        const profileId = $('#profile-id').val();
        if (!profileId) {
            showProfileOutput('Profile ID is required.');
            return;
        }

        $.ajax({
            type: 'POST',
            url: `/settings/profiles/${profileId}/test`,
            headers: csrfHeaders(),
            dataType: 'json',
            success: function(data) {
                $('#profile-status').text(`Profile ${profileId} connection OK.`);
                showProfileOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Profile connection test failed.';
                showProfileOutput(message);
            }
        });
    }

    function showAgentOutput(value) {
        const text = typeof value === 'string' ? value : JSON.stringify(value, null, 2);
        $('#agent-output').text(text).show();
    }

    function loadAgentSettings() {
        $.ajax({
            type: 'GET',
            url: '/settings/agents',
            dataType: 'json',
            success: function(data) {
                $('#agent-status').text(`Agent API: ${data.agent_api_enabled ? 'enabled' : 'disabled'} | Profiles: ${(data.profiles || []).length} | Tokens: ${(data.tokens || []).length}`);
                showAgentOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Agent settings request failed.';
                showAgentOutput(message);
            }
        });
    }

    function createAgentToken() {
        const payload = {
            name: $('#agent-token-name').val(),
            profile_ids: $('#agent-profile-ids').val(),
            expires_days: $('#agent-expires-days').val(),
            visibility_mode: $('#agent-visibility').val(),
            export_allowed: $('#agent-export-allowed').is(':checked')
        };

        $.ajax({
            type: 'POST',
            url: '/settings/agents/tokens',
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify(payload),
            dataType: 'json',
            success: function(data) {
                showAgentOutput(data);
                loadAgentSettings();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Token creation failed.';
                showAgentOutput(message);
            }
        });
    }

    function disableAgentApi() {
        $.ajax({
            type: 'POST',
            url: '/settings/agents/disable',
            headers: csrfHeaders(),
            dataType: 'json',
            success: function(data) {
                $('#agent-status').text('Agent API: disabled');
                showAgentOutput(data);
                loadAgentSettings();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Agent API disable failed.';
                showAgentOutput(message);
            }
        });
    }

    function revokeAgentToken(tokenId) {
        $.ajax({
            type: 'POST',
            url: `/settings/agents/tokens/${tokenId}/revoke`,
            headers: csrfHeaders(),
            dataType: 'json',
            success: function(data) {
                showAgentOutput(data);
                loadAgentSettings();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Token revoke failed.';
                showAgentOutput(message);
            }
        });
    }

    function loadAuditLog() {
        $.ajax({
            type: 'GET',
            url: '/audit',
            data: { limit: 100 },
            dataType: 'json',
            success: function(data) {
                showAgentOutput(data);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Audit request failed.';
                showAgentOutput(message);
            }
        });
    }

    function exportAuditLog(format) {
        window.location.href = `/audit/export?format=${encodeURIComponent(format)}&limit=10000`;
    }

    function showMemoryMessage(message, type = 'info') {
        $('#memory-message')
            .removeClass('alert-info alert-danger')
            .addClass(type === 'danger' ? 'alert-danger' : 'alert-info')
            .text(message)
            .show();
    }

    function loadWorkspaces() {
        $.ajax({
            type: 'GET',
            url: '/workspaces',
            dataType: 'json',
            success: function(data) {
                const selects = $('#workspace_id, #history-workspace-filter');
                const currentSearchWorkspace = $('#workspace_id').val();
                const currentHistoryWorkspace = $('#history-workspace-filter').val();
                $('#workspace_id').empty().append($('<option>').val('').text('No workspace'));
                $('#history-workspace-filter').empty().append($('<option>').val('').text('All workspaces'));
                (data.workspaces || []).forEach(workspace => {
                    $('#workspace_id').append($('<option>').val(workspace.workspace_id).text(workspace.name));
                    $('#history-workspace-filter').append($('<option>').val(workspace.workspace_id).text(workspace.name));
                });
                $('#workspace_id').val(currentSearchWorkspace);
                $('#history-workspace-filter').val(currentHistoryWorkspace);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Workspace request failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function createWorkspace() {
        const name = $('#workspace-name').val();
        if (!name) {
            showMemoryMessage('Workspace name is required.', 'danger');
            return;
        }
        $.ajax({
            type: 'POST',
            url: '/workspaces',
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify({ name }),
            dataType: 'json',
            success: function(data) {
                $('#workspace-name').val('');
                showMemoryMessage(`Workspace ${data.name} created.`);
                loadWorkspaces();
                setTimeout(function() {
                    $('#workspace_id').val(data.workspace_id);
                    $('#history-workspace-filter').val(data.workspace_id);
                }, 100);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Workspace create failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function renderHistoryRows(history) {
        const tbody = $('#history-table tbody');
        tbody.empty();
        (history || []).forEach(item => {
            const tr = $('<tr>');
            tr.append($('<td>').text(item.created_at || ''));
            tr.append($('<td>').text(item.profile_id || ''));
            tr.append($('<td>').text(item.actor_type || ''));
            tr.append($('<td>').text(item.query_text || ''));
            tr.append($('<td>').text(item.status || ''));
            tr.append($('<td>').text(item.raw_returned_count || item.result_count || 0));
            const actions = $('<td>');
            $('<button type="button" class="btn btn-sm btn-outline-secondary mr-1">Details</button>')
                .on('click', function() { viewHistoryDetail(item.search_id); })
                .appendTo(actions);
            $('<button type="button" class="btn btn-sm btn-outline-secondary mr-1">Rerun</button>')
                .prop('disabled', !item.can_rerun)
                .on('click', function() { rerunHistorySearch(item.search_id); })
                .appendTo(actions);
            $('<button type="button" class="btn btn-sm btn-outline-secondary">Save</button>')
                .prop('disabled', !item.can_rerun)
                .on('click', function() { saveHistorySearch(item.search_id); })
                .appendTo(actions);
            tr.append(actions);
            tbody.append(tr);
        });
    }

    function loadHistory() {
        const params = {};
        if ($('#history-profile-filter').val()) {
            params.profile_id = $('#history-profile-filter').val();
        }
        if ($('#history-workspace-filter').val()) {
            params.workspace_id = $('#history-workspace-filter').val();
        }
        if ($('#history-actor-filter').val()) {
            params.actor_type = $('#history-actor-filter').val();
        }
        $.ajax({
            type: 'GET',
            url: '/history',
            data: params,
            dataType: 'json',
            success: function(data) {
                renderHistoryRows(data.history || []);
                showMemoryMessage(`Loaded ${data.returned_count || 0} history entries.`);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'History request failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function viewHistoryDetail(searchId) {
        $.ajax({
            type: 'GET',
            url: `/history/${searchId}`,
            dataType: 'json',
            success: function(data) {
                $('#history-output').text(JSON.stringify(data, null, 2)).show();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'History detail request failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function saveHistorySearch(searchId) {
        const name = window.prompt('Saved search name', `Saved ${searchId}`);
        if (!name) {
            return;
        }
        $.ajax({
            type: 'POST',
            url: `/history/${searchId}/save`,
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify({ name }),
            dataType: 'json',
            success: function(data) {
                showMemoryMessage(`Saved search ${data.saved_search.name} created.`);
                loadSavedSearches();
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Save search failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function saveCurrentSearch() {
        if (!currentSearchId) {
            showMemoryMessage('No active search selected.', 'danger');
            return;
        }
        saveHistorySearch(currentSearchId);
    }

    function rerunHistorySearch(searchId) {
        $.ajax({
            type: 'POST',
            url: `/history/${searchId}/rerun`,
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify({ workspace_id: $('#workspace_id').val() }),
            dataType: 'json',
            success: function(data) {
                currentSearchId = data.search_id || null;
                showTab('results');
                applySearchPage(data);
                if (data.status === 'running' || data.status === 'queued') {
                    pollSearchPage();
                }
                showMemoryMessage(`Rerun ${data.search_id} started.`);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Rerun failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function renderSavedSearchRows(savedSearches) {
        const tbody = $('#saved-searches-table tbody');
        tbody.empty();
        (savedSearches || []).forEach(item => {
            const tr = $('<tr>');
            tr.append($('<td>').text(item.name || ''));
            tr.append($('<td>').text(item.profile_id || ''));
            tr.append($('<td>').text(item.query_text || ''));
            tr.append($('<td>').text(item.match_mode || ''));
            const actions = $('<td>');
            $('<button type="button" class="btn btn-sm btn-outline-secondary">Run</button>')
                .on('click', function() { runSavedSearch(item.saved_search_id); })
                .appendTo(actions);
            tr.append(actions);
            tbody.append(tr);
        });
    }

    function loadSavedSearches() {
        const params = {};
        const profileId = $('#history-profile-filter').val();
        if (profileId) {
            params.profile_id = profileId;
        }
        $.ajax({
            type: 'GET',
            url: '/saved-searches',
            data: params,
            dataType: 'json',
            success: function(data) {
                renderSavedSearchRows(data.saved_searches || []);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Saved searches request failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function runSavedSearch(savedSearchId) {
        $.ajax({
            type: 'POST',
            url: `/saved-searches/${savedSearchId}/run`,
            headers: csrfHeaders(),
            contentType: 'application/json',
            data: JSON.stringify({ workspace_id: $('#workspace_id').val() }),
            dataType: 'json',
            success: function(data) {
                currentSearchId = data.search_id || null;
                showTab('results');
                applySearchPage(data);
                if (data.status === 'running' || data.status === 'queued') {
                    pollSearchPage();
                }
                showMemoryMessage(`Saved search run ${data.search_id} started.`);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Saved search run failed.';
                showMemoryMessage(message, 'danger');
            }
        });
    }

    function preflightSearch() {
        const form = $('form');
        showTab('results');
        $('#loading-spinner').show();
        $('#error-message').hide();
        $('#no-results').hide();
        $('#search-summary').empty();

        $.ajax({
            type: 'POST',
            url: '/search/preflight',
            data: $.param(form.serializeArray()),
            dataType: 'json',
            success: function(data) {
                $('#loading-spinner').hide();
                const lines = [
                    `Profile: ${data.profile_name || data.profile_id || 'Legacy Human UI'}`,
                    `Connection: ${data.connection_mode || 'legacy'}`,
                    `Databases to scan: ${data.databases_to_scan || 0}`,
                    `Tables to scan: ${data.tables_to_scan || 0}`,
                    `Columns to scan: ${data.columns_to_scan || 0}`,
                    `Timeout: ${data.timeout_seconds || 0} sec`,
                    `Display limit: ${data.display_limit || 0}`,
                    `Export limit: ${data.export_limit || 0}`
                ];
                $('#search-summary').html(lines.map(line => $('<div>').text(line).prop('outerHTML')).join(''));
            },
            error: function(xhr) {
                $('#loading-spinner').hide();
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Preflight failed. Please try again later.';
                $('#error-message').text(message).show();
            }
        });
    }

    function performSearch() {
        const form = $('form');
        showTab('results');
        if (searchPollTimer) {
            clearTimeout(searchPollTimer);
            searchPollTimer = null;
        }
        if ($('#search-mode').val() === 'agent_assisted' && !$('#search_value').val() && $('#agent-goal').val()) {
            $('#search_value').val($('#agent-goal').val());
        }
        $('#loading-spinner').show();
        $('#error-message').hide();
        $('#no-results').hide();
        $('#search-summary').empty();
        let formData = form.serializeArray();
        
        $('#cancel-btn').prop('disabled', false);
        currentSearchRequest = $.ajax({
            type: 'POST',
            url: '/search/start',
            data: $.param(formData),
            dataType: 'json',
            success: function(data) {
                currentSearchRequest = null;
                if (data.error) {
                    $('#loading-spinner').hide();
                    $('#error-message').text(data.error).show();
                    $('#cancel-btn').prop('disabled', !currentSearchId);
                    return;
                }
                activeSearchValue = form.find('#search_value').val();
                currentSearchId = data.search_id || null;
                applySearchPage(data);
                if (data.status === 'running' || data.status === 'queued') {
                    pollSearchPage();
                } else {
                    $('#loading-spinner').hide();
                }
            },
            error: function(xhr) {
                $('#loading-spinner').hide();
                currentSearchRequest = null;
                if (xhr.statusText === 'abort') {
                    $('#error-message').text('Search request was cancelled in the browser. The server may finish cleanup in the background.').show();
                    $('#cancel-btn').prop('disabled', !currentSearchId);
                    return;
                }
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'An error occurred. Please try again later.';
                $('#error-message').text(message).show();
                $('#cancel-btn').prop('disabled', !currentSearchId);
            }
        });
    }

    function cancelSearch() {
        if (searchPollTimer) {
            clearTimeout(searchPollTimer);
            searchPollTimer = null;
        }
        if (currentSearchRequest) {
            currentSearchRequest.abort();
            currentSearchRequest = null;
            if (!currentSearchId) {
                $('#loading-spinner').hide();
                return;
            }
        }
        if (!currentSearchId) {
            return;
        }

        $.ajax({
            type: 'POST',
            url: `/search/${currentSearchId}/cancel`,
            headers: csrfHeaders(),
            dataType: 'json',
            success: function(data) {
                $('#loading-spinner').hide();
                if (data.error) {
                    $('#error-message').text(data.error).show();
                    return;
                }
                applySearchPage(data);
                $('#error-message').hide();
                $('#search-summary').text(`Search ${currentSearchId} cancelled.`);
                $('#cancel-btn').prop('disabled', true);
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Cancel failed. Please try again later.';
                $('#error-message').text(message).show();
            }
        });
    }

    function pollSearchPage() {
        if (!currentSearchId) {
            $('#loading-spinner').hide();
            return;
        }
        $.ajax({
            type: 'GET',
            url: `/search/page/${currentSearchId}`,
            dataType: 'json',
            success: function(data) {
                if (data.error) {
                    $('#loading-spinner').hide();
                    $('#error-message').text(data.error).show();
                    return;
                }
                applySearchPage(data);
                if (data.status === 'running' || data.status === 'queued') {
                    searchPollTimer = setTimeout(pollSearchPage, 1000);
                } else {
                    $('#loading-spinner').hide();
                    searchPollTimer = null;
                }
            },
            error: function(xhr) {
                $('#loading-spinner').hide();
                searchPollTimer = null;
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Search status request failed.';
                $('#error-message').text(message).show();
            }
        });
    }

    function exportSearch(format, scope) {
        if (!currentSearchId) {
            return;
        }

        $.ajax({
            type: 'POST',
            url: `/search/${currentSearchId}/export`,
            headers: csrfHeaders(),
            data: { format: format, scope: scope || 'full_results', page: currentPage },
            dataType: 'json',
            success: function(data) {
                if (data.error) {
                    $('#error-message').text(data.error).show();
                    return;
                }
                window.location.href = data.download_url;
            },
            error: function(xhr) {
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'Export failed. Please try again later.';
                $('#error-message').text(message).show();
            }
        });
    }

    function loadSearchPage(cursor) {
        if (!currentSearchId || !cursor) {
            return;
        }
        $('#loading-spinner').show();
        $('#error-message').hide();

        $.ajax({
            type: 'GET',
            url: `/search/page/${currentSearchId}`,
            data: { cursor: cursor },
            dataType: 'json',
            success: function(data) {
                $('#loading-spinner').hide();
                if (data.error) {
                    $('#error-message').text(data.error).show();
                    return;
                }
                applySearchPage(data);
            },
            error: function(xhr) {
                $('#loading-spinner').hide();
                const message = xhr.responseJSON && xhr.responseJSON.error
                    ? xhr.responseJSON.error
                    : 'An error occurred. Please try again later.';
                $('#error-message').text(message).show();
            }
        });
    }

    function applySearchPage(data) {
        currentSearchId = data.search_id || currentSearchId;
        currentPage = data.page || 1;
        totalPages = data.total_pages || 1;
        nextCursor = data.next_cursor || null;
        previousCursor = data.previous_cursor || null;

        const isRunning = data.status === 'running' || data.status === 'queued';
        const isFailed = data.status === 'failed';
        const isCancelled = data.status === 'cancelled';
        if (isRunning || isFailed || isCancelled) {
            $('#results-table tbody').empty();
            $('#no-results').hide();
            $('.pagination-controls').hide();
        } else {
            updateResults(data.results || []);
        }

        let summary = [
            `Profile: ${data.profile_name || data.profile_id || 'Legacy Human UI'}`,
            `Connection: ${data.connection_mode || 'legacy'}`,
            `Status: ${data.status || 'completed'}`,
            `Searched for: ${activeSearchValue}`,
            `Page: ${currentPage} of ${totalPages}`,
            `Displayed: ${data.returned_count || 0} of ${data.total_count || 0}`,
            `Scanned databases: ${data.scanned_databases || 0}`,
            `Scanned tables: ${data.scanned_tables || 0}`,
            `Scanned columns: ${data.scanned_columns || 0}`
        ];
        if (data.truncated) {
            summary.push(`Result truncated at ${data.display_limit} raw rows`);
            summary.push('Stored export contains only stored preview rows');
        }
        $('#search-summary').text(summary.join(' | '));
        if (isFailed) {
            $('#error-message').text(data.error || 'Search failed.').show();
        }
        const hasSearch = Boolean(currentSearchId);
        $('#cancel-btn').prop('disabled', isCancelled || isFailed || !hasSearch);
        $('#export-page-csv-btn').prop('disabled', isCancelled || isRunning || isFailed || !hasSearch || (data.returned_count || 0) === 0);
        $('#export-csv-btn').prop('disabled', isCancelled || isRunning || isFailed || !hasSearch || (data.total_count || 0) === 0);
        $('#export-jsonl-btn').prop('disabled', isCancelled || isRunning || isFailed || !hasSearch || (data.total_count || 0) === 0);
        updatePageInfo();
    }

    function updateResults(results) {
        const tableBody = $('#results-table tbody');
        tableBody.empty();
        if (results.length === 0) {
            $('#no-results').show();
            $('.pagination-controls').hide();
            return;
        }
        $('#no-results').hide();
        $('.pagination-controls').show();

        results.forEach(row => {
            const tr = $('<tr>');
            row.forEach(cell => {
                tr.append($('<td>').text(cell));
            });
            tableBody.append(tr);
        });
        updatePageInfo();
    }

    function nextPage() {
        if (nextCursor) {
            loadSearchPage(nextCursor);
        }
    }

    function prevPage() {
        if (previousCursor) {
            loadSearchPage(previousCursor);
        }
    }

    function updatePageInfo() {
        $('#page-info').text(`Page ${currentPage} of ${totalPages}`);
        $('#prev-btn').prop('disabled', !previousCursor);
        $('#next-btn').prop('disabled', !nextCursor);
    }

</script>
<br>
<footer>
    <div class="container text-center">
        <p class="footer-text">D.S.T. by Viken Data Studio &copy; <span id="year"></span>. License: Freeware. No warranty or liability. Contact: <a href="mailto:support@vikendata.com">support@vikendata.com</a>.</p>
    </div>
</footer>
<script>
    // Update the copyright year dynamically
    document.getElementById('year').textContent = new Date().getFullYear();
</script>
</body>
</html>
