<%@ Page Language="C#" %>
<!DOCTYPE html>
<html>
<head>
    <title>Migration Control Pad</title>
    <style>
        body { font-family: 'Segoe UI', Arial, sans-serif; margin: 0; padding: 24px; background: #f5f5f5; }
        .container { max-width: 1100px; margin: 0 auto; background: #fff; padding: 28px; border-radius: 10px; box-shadow: 0 2px 10px rgba(0,0,0,.1); }
        h1 { margin-top: 0; color: #222; }
        .subtitle { color: #666; margin-bottom: 20px; }
        .section { margin: 20px 0; padding: 18px; background: #f8fbff; border-left: 4px solid #0b6fc2; border-radius: 6px; }
        .status-grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 14px; }
        .card { background: #fff; border: 1px solid #dbe6f3; border-radius: 8px; padding: 14px; }
        .card h3 { margin: 0 0 8px 0; font-size: 16px; }
        .value { font-size: 26px; font-weight: 700; color: #0b6fc2; }
        .rotary { display: flex; gap: 12px; align-items: center; }
        .rotary button { min-width: 140px; }
        .rotary .active-empty { background: #f0ad4e; }
        .rotary .active-filled { background: #4caf50; }
        button { background: #0b6fc2; color: #fff; border: 0; border-radius: 6px; padding: 11px 18px; cursor: pointer; font-weight: 600; }
        button:hover { background: #095a9c; }
        button.secondary { background: #6c757d; }
        button.warn { background: #f0ad4e; }
        button.good { background: #4caf50; }
        select, input { padding: 9px 10px; border: 1px solid #cfd8e3; border-radius: 6px; min-width: 240px; }
        .controls { display: flex; gap: 12px; flex-wrap: wrap; align-items: end; }
        .field { display: flex; flex-direction: column; gap: 6px; }
        .muted { color: #666; font-size: 12px; }
        .log { background: #111; color: #d7f7d7; border-radius: 8px; padding: 14px; min-height: 220px; max-height: 420px; overflow-y: auto; font-family: Consolas, monospace; font-size: 12px; white-space: pre-wrap; }
        .badge { display: inline-block; padding: 6px 10px; border-radius: 20px; font-size: 12px; font-weight: 700; }
        .badge.empty { background: #fff3cd; color: #8a6d3b; }
        .badge.filled { background: #dff0d8; color: #3c763d; }
        .badge.unknown { background: #eee; color: #555; }
        ul { margin: 8px 0 0 20px; }
    </style>
</head>
<body>
<div class="container">
    <h1>Migration Control Pad</h1>
    <div class="subtitle">Rotary switch and Siphon actions for <code>Web\Data\sqlitedb</code>. <span id="ordinalTag" class="badge unknown" style="margin-left:8px;">Ord 015</span></div>

    <div class="section">
        <div><strong>Rotary Switch State:</strong> <span id="stateBadge" class="badge unknown">Loading</span></div>
        <div class="rotary" style="margin-top:12px;">
            <button id="emptyButton" class="warn" onclick="resetEmpty()">Empty</button>
            <button id="filledButton" class="secondary" onclick="refreshStatus()">Filled</button>
        </div>
        <div class="muted" id="dbFolderLabel" style="margin-top:10px;"></div>
    </div>

    <div class="section">
        <div class="status-grid">
            <div class="card">
                <h3>Current</h3>
                <div class="value" id="currentPages">-</div>
                <div class="muted">Pages in <code>mojo.db.config</code></div>
            </div>
            <div class="card">
                <h3>Legacy Source</h3>
                <div class="value" id="legacyPages">-</div>
                <div class="muted">Pages in selected source</div>
            </div>
            <div class="card">
                <h3>Empty Baseline</h3>
                <div class="value" id="emptyPages">-</div>
                <div class="muted">Pages in <code>empty.db.config</code></div>
            </div>
        </div>
    </div>

    <div class="section">
        <div class="controls">
            <div class="field">
                <label for="sourceFile">Siphon Source</label>
                <select id="sourceFile"></select>
                <div class="muted">All source .db.config files are loaded from <code>Web\Data\sqlitedb</code>.</div>
            </div>
            <div class="field">
                <label for="siteId">Target Site ID</label>
                <input id="siteId" type="number" value="1" min="1" />
            </div>
            <button onclick="analyzeSource()">Analyze</button>
            <button class="good" onclick="siphonSource()">Siphon</button>
        </div>
        <div id="sourceStats" class="muted" style="margin-top:10px;"></div>
    </div>

    <div class="section">
        <strong>Source files</strong>
        <ul id="sourceList"></ul>
    </div>

    <div class="section">
        <strong>HUD Diagnostics</strong>
        <div id="hudDiagnostics" class="muted"></div>
    </div>

    <div class="section">
        <strong>Migration Log</strong>
        <div id="log" class="log"></div>
    </div>
</div>

<script>
const ORDINAL = '015';
const API_ENDPOINTS = ['<%= ResolveUrl("~/Admin/MigrationAnalyzer.aspx") %>'];
const STARTUP_DELAY_MS = 2000;

function getApiUrl(endpoint) {
    return endpoint;
}

function setHudDiagnostics(message) {
    document.getElementById('hudDiagnostics').textContent = message || '';
}

function getUrlParam(name) {
    const params = new URLSearchParams(window.location.search || '');
    return params.get(name);
}

function toOneLine(text) {
    return (text || '').replace(/\s+/g, ' ').trim();
}

function formatApiError(parsed, bodyPreview) {
    if (parsed) {
        const parts = [];
        if (parsed.error) parts.push(parsed.error);
        if (parsed.detail) parts.push(toOneLine(parsed.detail));
        return parts.join(' | ');
    }

    return bodyPreview;
}

async function callApi(payload) {
    let lastError = null;

    for (const endpoint of API_ENDPOINTS) {
        const apiUrl = getApiUrl(endpoint);
        try {
            setHudDiagnostics('Trying ' + apiUrl + ' action=' + (payload && payload.action ? payload.action : ''));

            const response = await fetch(apiUrl, {
                method: 'POST',
                headers: { 'Content-Type': 'application/json' },
                body: JSON.stringify(payload)
            });

            const contentType = (response.headers.get('content-type') || '').toLowerCase();
            const text = await response.text();
            const bodyPreview = text.length > 1200 ? text.substring(0, 1200) + '...' : text;
            let parsed = null;

            if (contentType.indexOf('application/json') > -1 && text.length > 0) {
                try {
                    parsed = JSON.parse(text);
                } catch { }
            }

            if (!response.ok) {
                const detail = formatApiError(parsed, bodyPreview);
                lastError = new Error(apiUrl + ' HTTP ' + response.status + ' ' + detail);
                setHudDiagnostics('HTTP ' + response.status + ' from ' + apiUrl + ' (' + contentType + ')');
                appendLog('API ERR: ' + apiUrl + ' status=' + response.status + ' action=' + (payload && payload.action ? payload.action : ''));
                appendLog('API REQ: ' + JSON.stringify(payload));
                appendLog('API DETAIL: ' + detail);
                continue;
            }

            if (!parsed) {
                lastError = new Error(apiUrl + ' returned non-JSON response');
                setHudDiagnostics('Non-JSON from ' + apiUrl);
                appendLog('API ERR: Non-JSON response from ' + apiUrl);
                appendLog('API REQ: ' + JSON.stringify(payload));
                appendLog('API DETAIL: ' + toOneLine(bodyPreview));
                continue;
            }

            setHudDiagnostics('OK ' + apiUrl + ' action=' + (payload && payload.action ? payload.action : '') + ' success=' + parsed.success);
            return parsed;
        } catch (err) {
            lastError = err;
            setHudDiagnostics('Error via ' + apiUrl + ': ' + err.message);
            appendLog('API ERR: ' + apiUrl + ' action=' + (payload && payload.action ? payload.action : '') + ' message=' + err.message);
            appendLog('API REQ: ' + JSON.stringify(payload));
        }
    }

    throw lastError || new Error('Migration API unreachable');
}

function appendLog(message) {
    const el = document.getElementById('log');
    el.textContent += message + "\n";
    el.scrollTop = el.scrollHeight;
}

function setStateBadge(state) {
    const badge = document.getElementById('stateBadge');
    const emptyButton = document.getElementById('emptyButton');
    const filledButton = document.getElementById('filledButton');
    badge.textContent = state;
    badge.className = 'badge ' + (state || '').toLowerCase();
    emptyButton.className = 'warn';
    filledButton.className = 'secondary';
    if (state === 'Empty') emptyButton.className = 'warn active-empty';
    if (state === 'Filled') filledButton.className = 'good active-filled';
}

async function refreshStatus() {
    const data = await callApi({ action: 'status' });
    if (!data.success) {
        appendLog('ERROR: ' + data.error);
        return;
    }

    setStateBadge(data.state || 'Unknown');
    document.getElementById('dbFolderLabel').textContent = 'DB Folder: ' + (data.dbFolder || '');
    document.getElementById('currentPages').textContent = data.currentDb && data.currentDb.stats ? (data.currentDb.stats.Pages || 0) : 0;
    document.getElementById('legacyPages').textContent = data.legacyDb && data.legacyDb.stats ? (data.legacyDb.stats.Pages || 0) : 0;
    document.getElementById('emptyPages').textContent = data.emptyDb && data.emptyDb.stats ? (data.emptyDb.stats.Pages || 0) : 0;

    const select = document.getElementById('sourceFile');
    select.innerHTML = '';
    const sourceList = document.getElementById('sourceList');
    sourceList.innerHTML = '';

    (data.sources || []).forEach(src => {
        const option = document.createElement('option');
        option.value = src.fileName;
        option.textContent = src.fileName;
        select.appendChild(option);

        const li = document.createElement('li');
        const stats = src.stats || {};
        li.textContent = src.fileName + ' — Pages: ' + (stats.Pages || 0) + ', Modules: ' + (stats.Modules || 0) + ', Settings: ' + (stats.ModuleSettings || 0);
        sourceList.appendChild(li);
    });

    if (select.options.length === 0) {
        const option = document.createElement('option');
        option.value = 'legacy.db.config';
        option.textContent = 'legacy.db.config';
        select.appendChild(option);
    }

    document.getElementById('sourceStats').textContent = '';
}

async function analyzeSource() {
    const sourceFile = document.getElementById('sourceFile').value;
    const data = await callApi({ action: 'analyze', sourceFile: sourceFile });
    if (!data.success) {
        appendLog('ERROR: ' + data.error);
        return;
    }

    document.getElementById('sourceStats').textContent = 'Source ' + data.sourceFile + ' → Pages: ' + data.pages + ', Modules: ' + data.modules + ', Module Settings: ' + data.moduleSettings + ', Site Settings: ' + data.siteSettings;
    appendLog('Analyze: ' + data.sourceFile + ' → pages=' + data.pages + ', modules=' + data.modules + ', moduleSettings=' + data.moduleSettings + ', siteSettings=' + data.siteSettings);
}

async function resetEmpty(force) {
    if (!force && !confirm('Reset mojo.db.config from empty.db.config? A backup will be created first.')) return;
    const data = await callApi({ action: 'resetEmpty' });
    if (!data.success) {
        appendLog('ERROR: ' + data.error);
        return;
    }

    appendLog('Empty: ' + data.message + ' (backup: ' + data.backupFile + ')');
    await refreshStatus();
}

async function siphonSource(force) {
    const sourceFile = document.getElementById('sourceFile').value;
    const siteId = parseInt(document.getElementById('siteId').value || '1', 10);
    if (!force && !confirm('Siphon data from ' + sourceFile + ' into mojo.db.config?')) return;

    const data = await callApi({ action: 'siphon', sourceFile: sourceFile, siteId: siteId });
    if (!data.success) {
        appendLog('ERROR: ' + data.error);
        return;
    }

    appendLog('Siphon complete from ' + data.sourceFile + ': pages=' + data.pages + ', modules=' + data.modules + ', siteSettings=' + data.siteSettings);
    (data.logs || []).forEach(line => appendLog(line));
    await refreshStatus();
}

async function startupHud() {
    appendLog('Ordinal ' + ORDINAL + ' ready.');
    await refreshStatus();

    const click = (getUrlParam('click') || '').toLowerCase();
    const autoConfirm = getUrlParam('autoconfirm') === '1';

    if (!click) {
        return;
    }

    appendLog('Auto mode click=' + click + ' after ' + STARTUP_DELAY_MS + 'ms');
    setHudDiagnostics('Auto click=' + click + ' pending');

    await new Promise(resolve => setTimeout(resolve, STARTUP_DELAY_MS));

    if (click === 'but1') {
        appendLog('Auto click=but1: Analyze');
        await analyzeSource();
    } else if (click === 'but2') {
        appendLog('Auto click=but2: Siphon');
        await siphonSource(autoConfirm);
    } else if (click === 'but0') {
        appendLog('Auto click=but0: Empty');
        await resetEmpty(autoConfirm);
    }
}

startupHud().catch(err => {
    appendLog('ERROR: ' + err.message);
    setHudDiagnostics('Startup error: ' + err.message);
});
</script>
</body>
</html>
