import { apiGet, apiUrl, apiDownloadFetch } from '../api.js';
import { homeNavButton, showToast } from '../app.js';
import { buildResultColumns, resultColumnCellValue } from '../test-data.js';

const PAGE_SIZE = 50;

let sortCol = null;
let sortDir = 'asc';
let allClients = [];
let allSubmissions = [];
let showAllVersions = true;
let showMetadata = true;
let questionnaireId = '';
let questionsDef = [];
let resultColumns = [];
let questionnaireMeta = null;
let filterCoach = '';
let filterSupervisor = '';
let filterStatus = '';
let filterDateFrom = '';
let filterDateTo = '';
let filterSearch = '';
let filterQuestion = '';
let page = 0;

export async function resultsPage(params) {
    const app = document.getElementById('app');
    sortCol = null;
    sortDir = 'asc';
    filterCoach = '';
    filterSupervisor = '';
    filterStatus = '';
    filterDateFrom = '';
    filterDateTo = '';
    filterSearch = '';
    filterQuestion = '';
    page = 0;
    showAllVersions = true;
    showMetadata = true;
    questionnaireId = params.id;

    app.innerHTML = `
        <div class="page-header">
            <div class="page-header-start">
                ${homeNavButton()}
                <div class="page-header-titles">
                    <h1 id="resultsTitle">Results</h1>
                </div>
            </div>
            <div class="actions">
                <a href="#/questionnaire/${params.id}" class="btn">Editor</a>
                <a href="#/questionnaires" class="btn">Session measures</a>
            </div>
        </div>
        <div id="resultsContent"><div class="spinner"></div></div>
    `;

    try {
        await loadResultsData();
    } catch (e) {
        showToast(e.message, 'error');
        document.getElementById('resultsContent').innerHTML = `<p class="error-text">${esc(e.message)}</p>`;
    }
}

async function loadResultsData() {
    const versionParam = showAllVersions ? '&allVersions=1' : '';
    const data = await apiGet(`results.php?questionnaireID=${encodeURIComponent(questionnaireId)}${versionParam}`);
    questionnaireMeta = data.questionnaire;
    questionsDef = data.questions || [];
    if (data.allVersions) {
        allSubmissions = data.submissions || [];
        allClients = [];
    } else {
        allClients = data.clients || [];
        allSubmissions = [];
    }
    document.getElementById('resultsTitle').textContent = `Results: ${questionnaireMeta.name} v${questionnaireMeta.version}`;
    renderResults();
}

function renderResults() {
    const container = document.getElementById('resultsContent');
    resultColumns = buildResultColumns(questionsDef);

    // Collect unique coaches and statuses for filters
    const coachOptions = getCoachFilterOptions();
    const supervisorOptions = getSupervisorFilterOptions();
    const statuses = [...new Set(getSourceRows().map(c => c.status))].filter(Boolean).sort();

    container.innerHTML = `
        <div class="card" style="margin-bottom:16px">
            <div class="filter-bar">
                <label style="font-size:.85rem;font-weight:500">Filter:</label>
                <label style="font-size:.85rem;display:flex;align-items:center;gap:6px">
                    <input type="checkbox" id="toggleAllVersions" ${showAllVersions ? 'checked' : ''}>
                    All versions (grouped by client)
                </label>
                <label style="font-size:.85rem;display:flex;align-items:center;gap:6px">
                    <input type="checkbox" id="toggleShowMetadata" ${showMetadata ? 'checked' : ''}>
                    Show metadata
                </label>
                <select id="filterSupervisor">
                    <option value="">All supervisors</option>
                    ${supervisorOptions.map(name => `<option value="${esc(name)}" ${filterSupervisor === name ? 'selected' : ''}>${esc(name)}</option>`).join('')}
                </select>
                <select id="filterCoach">
                    <option value="">All counselors</option>
                    ${coachOptions.map(([id, label]) => `<option value="${esc(id)}" ${filterCoach === id ? 'selected' : ''}>${esc(label)}</option>`).join('')}
                </select>
                <select id="filterStatus">
                    <option value="">All statuses</option>
                    ${statuses.map(s => `<option value="${esc(s)}" ${filterStatus === s ? 'selected' : ''}>${esc(s)}</option>`).join('')}
                </select>
                <label style="font-size:.85rem;display:flex;align-items:center;gap:4px">
                    Completed from
                    <input type="date" id="filterDateFrom" value="${esc(filterDateFrom)}">
                </label>
                <label style="font-size:.85rem;display:flex;align-items:center;gap:4px">
                    to
                    <input type="date" id="filterDateTo" value="${esc(filterDateTo)}">
                </label>
                <input type="search" id="filterSearch" class="filter-search" placeholder="Search client, counselors, status…" value="${esc(filterSearch)}">
                <input type="search" id="filterQuestion" placeholder="Go to question key…" value="${esc(filterQuestion)}" style="min-width:160px" list="questionKeyList">
                <datalist id="questionKeyList"></datalist>
                <button type="button" class="btn btn-sm" id="gotoQuestionBtn">Go to column</button>
                <button type="button" class="btn btn-sm" id="clearFiltersBtn">Clear filters</button>
                <span style="margin-left:auto;font-size:.85rem;color:var(--text-secondary)" id="resultCount"></span>
                <button type="button" class="btn btn-sm" id="exportCsvLink">Export CSV</button>
            </div>
            <p class="data-toolbar-hint" style="margin-top:8px">
                ${showAllVersions
                    ? `Each row is one uploaded version, sorted by client then version.${showMetadata ? ' Metadata includes version, cycle, session, start/end/upload times, and submission details.' : ' Turn on metadata to see version, cycle, session, and timestamps.'}`
                    : `Latest response per client.${showMetadata ? ' Metadata includes cycle, session, and start/end times.' : ' Turn on metadata to see cycle, session, and timestamps.'} Each question has its own column.`}
            </p>
        </div>
        <div class="card">
            <div class="table-wrapper" id="resultsTableWrap">
                <table class="data-table" id="resultsTable">
                    <thead><tr id="resultsHead"></tr></thead>
                    <tbody id="resultsBody"></tbody>
                </table>
            </div>
            <div class="pagination-bar" id="paginationBar"></div>
        </div>
    `;

    const qKeyList = document.getElementById('questionKeyList');
    qKeyList.innerHTML = resultColumns
        .map(col => `<option value="${esc(col.label)}"></option>`)
        .join('');

    document.getElementById('filterSupervisor').addEventListener('change', (e) => {
        filterSupervisor = e.target.value;
        page = 0;
        renderTableRows();
    });
    document.getElementById('filterCoach').addEventListener('change', (e) => {
        filterCoach = e.target.value;
        page = 0;
        renderTableRows();
    });
    document.getElementById('filterStatus').addEventListener('change', (e) => {
        filterStatus = e.target.value;
        page = 0;
        renderTableRows();
    });
    document.getElementById('filterDateFrom').addEventListener('change', (e) => {
        filterDateFrom = e.target.value;
        page = 0;
        renderTableRows();
    });
    document.getElementById('filterDateTo').addEventListener('change', (e) => {
        filterDateTo = e.target.value;
        page = 0;
        renderTableRows();
    });
    document.getElementById('filterSearch').addEventListener('input', (e) => {
        filterSearch = e.target.value.trim();
        page = 0;
        renderTableRows();
    });
    document.getElementById('gotoQuestionBtn').addEventListener('click', () => {
        filterQuestion = document.getElementById('filterQuestion').value.trim();
        scrollToQuestionColumn(filterQuestion);
    });
    document.getElementById('filterQuestion').addEventListener('keydown', (e) => {
        if (e.key === 'Enter') {
            e.preventDefault();
            filterQuestion = e.target.value.trim();
            scrollToQuestionColumn(filterQuestion);
        }
    });
    document.getElementById('clearFiltersBtn').addEventListener('click', () => {
        filterCoach = '';
        filterSupervisor = '';
        filterStatus = '';
        filterDateFrom = '';
        filterDateTo = '';
        filterSearch = '';
        filterQuestion = '';
        page = 0;
        renderResults();
    });
    document.getElementById('toggleAllVersions').addEventListener('change', async (e) => {
        showAllVersions = e.target.checked;
        page = 0;
        sortCol = null;
        document.getElementById('resultsContent').innerHTML = '<div class="spinner"></div>';
        try {
            await loadResultsData();
        } catch (err) {
            showToast(err.message, 'error');
        }
    });
    document.getElementById('toggleShowMetadata').addEventListener('change', (e) => {
        showMetadata = e.target.checked;
        if (!showMetadata && sortCol && META_COL_KEYS.has(sortCol)) {
            sortCol = null;
        }
        renderTableHead();
        renderTableRows();
        const hint = document.querySelector('#resultsContent .data-toolbar-hint');
        if (hint) {
            hint.textContent = showAllVersions
                ? `Each row is one uploaded version, sorted by client then version.${showMetadata ? ' Metadata includes version, cycle, session, start/end/upload times, and submission details.' : ' Turn on metadata to see version, cycle, session, and timestamps.'}`
                : `Latest response per client.${showMetadata ? ' Metadata includes cycle, session, and start/end times.' : ' Turn on metadata to see cycle, session, and timestamps.'} Each question has its own column.`;
        }
    });
    document.getElementById('exportCsvLink').addEventListener('click', (e) => {
        e.preventDefault();
        exportCSV();
    });

    renderTableHead();
    renderTableRows();
}

function getSourceRows() {
    return showAllVersions ? allSubmissions : allClients;
}

const META_COL_KEYS = new Set([
    'version',
    'programCycleNumber',
    'programSessionNumber',
    'programSessionID',
    'startedAt',
    'completedAt',
    'submittedAt',
    'submissionID',
    'structureRevision',
    'submittedByRole',
    'submittedBy',
]);

const IDENTITY_FIXED_COLUMNS = [
    { key: 'coachUsername', label: 'Counselor' },
    { key: 'supervisorUsername', label: 'Supervisor' },
    { key: 'status', label: 'Status' },
    { key: 'sumPoints', label: 'Score' },
];

const META_COLUMNS_ALL_VERSIONS = [
    { key: 'version', label: 'Version' },
    { key: 'programCycleNumber', label: 'Cycle' },
    { key: 'programSessionNumber', label: 'Session' },
    { key: 'programSessionID', label: 'Session ID' },
    { key: 'startedAt', label: 'Started' },
    { key: 'completedAt', label: 'Completed' },
    { key: 'submittedAt', label: 'Uploaded' },
    { key: 'submissionID', label: 'Submission ID' },
    { key: 'structureRevision', label: 'Structure rev.' },
    { key: 'submittedByRole', label: 'Submitted by role' },
    { key: 'submittedBy', label: 'Submitted by' },
];

const META_COLUMNS_CURRENT = [
    { key: 'programCycleNumber', label: 'Cycle' },
    { key: 'programSessionNumber', label: 'Session' },
    { key: 'programSessionID', label: 'Session ID' },
    { key: 'startedAt', label: 'Started' },
    { key: 'completedAt', label: 'Completed' },
];

function getTableFixedColumns() {
    const clientCol = [{ key: 'clientCode', label: 'Client' }];
    if (!showMetadata) {
        return [...clientCol, ...IDENTITY_FIXED_COLUMNS];
    }
    const meta = showAllVersions ? META_COLUMNS_ALL_VERSIONS : META_COLUMNS_CURRENT;
    return [...clientCol, ...meta, ...IDENTITY_FIXED_COLUMNS];
}

function renderTableHead() {
    const head = document.getElementById('resultsHead');
    const fixedCols = getTableFixedColumns();
    const allCols = [...fixedCols, ...resultColumns.map(col => ({
        key: col.key,
        label: col.label,
        title: col.title,
    }))];

    head.innerHTML = allCols.map((col, idx) => {
        let cls = 'sortable';
        if (sortCol === col.key) cls += sortDir === 'asc' ? ' sort-asc' : ' sort-desc';
        if (idx === 0) cls += ' sticky-col';
        const title = col.title ? ` title="${esc(col.title)}"` : '';
        return `<th class="${cls}" data-key="${col.key}"${title}>${esc(col.label)}</th>`;
    }).join('');

    head.querySelectorAll('th.sortable').forEach(th => {
        th.addEventListener('click', () => {
            const key = th.dataset.key;
            if (sortCol === key) sortDir = sortDir === 'asc' ? 'desc' : 'asc';
            else { sortCol = key; sortDir = 'asc'; }
            page = 0;
            renderTableHead();
            renderTableRows();
        });
    });
}

function scrollToQuestionColumn(query) {
    if (!query) return;
    const q = query.toLowerCase();
    const th = [...document.querySelectorAll('#resultsHead th')].find(el => {
        const key = (el.dataset.key || '').toLowerCase();
        const text = (el.textContent || '').trim().toLowerCase();
        const title = (el.getAttribute('title') || '').toLowerCase();
        return text === q || title === q || key.endsWith(q) || text.includes(q);
    });
    if (!th) {
        showToast(`No column matching "${query}"`, 'error');
        return;
    }
    th.scrollIntoView({ behavior: 'smooth', block: 'nearest', inline: 'center' });
    th.style.outline = '2px solid var(--primary)';
    setTimeout(() => { th.style.outline = ''; }, 2000);
}

function getCoachFilterOptions() {
    const map = new Map();
    getSourceRows().forEach(c => {
        if (!c.coachID || map.has(c.coachID)) return;
        map.set(c.coachID, c.coachUsername || c.coachID);
    });
    return [...map.entries()].sort((a, b) => a[1].localeCompare(b[1]));
}

function getSupervisorFilterOptions() {
    return [...new Set(getSourceRows().map(c => c.supervisorUsername).filter(Boolean))].sort((a, b) =>
        a.localeCompare(b)
    );
}

function coachDisplayName(c) {
    return c.coachUsername || c.coachID || '—';
}

function supervisorDisplayName(c) {
    return c.supervisorUsername || '—';
}

function getFilteredRows() {
    let rows = [...getSourceRows()];
    if (filterSupervisor) rows = rows.filter(c => c.supervisorUsername === filterSupervisor);
    if (filterCoach) rows = rows.filter(c => c.coachID === filterCoach);
    if (filterStatus) rows = rows.filter(c => c.status === filterStatus);
    if (filterDateFrom || filterDateTo) {
        const fromTs = filterDateFrom ? dateInputToUnixStart(filterDateFrom) : null;
        const toTs = filterDateTo ? dateInputToUnixEnd(filterDateTo) : null;
        rows = rows.filter(c => {
            const ts = c.completedAt;
            if (!ts) return false;
            if (fromTs !== null && ts < fromTs) return false;
            if (toTs !== null && ts > toTs) return false;
            return true;
        });
    }
    if (filterSearch) {
        const q = filterSearch.toLowerCase();
        rows = rows.filter(c => {
            const hay = [
                c.clientCode,
                c.coachUsername,
                c.supervisorUsername,
                c.status,
                showAllVersions ? String(c.version ?? '') : '',
                c.programCycleNumber != null ? String(c.programCycleNumber) : '',
                c.programSessionNumber != null ? String(c.programSessionNumber) : '',
                c.programSessionID,
            ].filter(Boolean).join(' ').toLowerCase();
            return hay.includes(q);
        });
    }
    if (showAllVersions) {
        rows.sort((a, b) => {
            const cc = a.clientCode.localeCompare(b.clientCode);
            if (cc !== 0) return cc;
            return (a.version ?? 0) - (b.version ?? 0);
        });
    }
    return rows;
}

function renderPagination(totalRows) {
    const bar = document.getElementById('paginationBar');
    if (!bar) return;
    const totalPages = Math.max(1, Math.ceil(totalRows / PAGE_SIZE));
    if (page >= totalPages) page = totalPages - 1;
    if (page < 0) page = 0;

    if (totalRows <= PAGE_SIZE) {
        bar.innerHTML = totalRows
            ? `<span>${totalRows} row${totalRows === 1 ? '' : 's'}</span>`
            : '';
        return;
    }

    const from = page * PAGE_SIZE + 1;
    const to = Math.min((page + 1) * PAGE_SIZE, totalRows);
    bar.innerHTML = `
        <button type="button" class="btn btn-sm" id="pagePrev" ${page <= 0 ? 'disabled' : ''}>Prev</button>
        <span>Rows ${from}–${to} of ${totalRows} (page ${page + 1}/${totalPages})</span>
        <button type="button" class="btn btn-sm" id="pageNext" ${page >= totalPages - 1 ? 'disabled' : ''}>Next</button>
    `;
    document.getElementById('pagePrev')?.addEventListener('click', () => {
        page--;
        renderTableRows();
    });
    document.getElementById('pageNext')?.addEventListener('click', () => {
        page++;
        renderTableRows();
    });
}

function dateInputToUnixStart(yyyyMmDd) {
    const [y, m, d] = yyyyMmDd.split('-').map(Number);
    return Math.floor(new Date(y, m - 1, d).getTime() / 1000);
}

function dateInputToUnixEnd(yyyyMmDd) {
    const [y, m, d] = yyyyMmDd.split('-').map(Number);
    return Math.floor(new Date(y, m - 1, d, 23, 59, 59, 999).getTime() / 1000);
}

function formatUnixDateTime(ts) {
    if (!ts) return '—';
    return new Date(ts * 1000).toLocaleString(undefined, {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
    });
}

function fixedColumnCellHtml(c, col, { groupStart = false } = {}) {
    switch (col.key) {
        case 'clientCode':
            return `<td class="sticky-col${groupStart ? ' client-group-start' : ''}">${esc(c.clientCode)}</td>`;
        case 'version':
            return `<td>${c.version ?? '—'}</td>`;
        case 'programCycleNumber':
            return `<td>${c.programCycleNumber ?? '—'}</td>`;
        case 'programSessionNumber':
            return `<td>${c.programSessionNumber ?? '—'}</td>`;
        case 'programSessionID':
            return `<td>${c.programSessionID ? esc(c.programSessionID) : '—'}</td>`;
        case 'coachUsername':
            return `<td>${esc(coachDisplayName(c))}</td>`;
        case 'supervisorUsername':
            return `<td>${esc(supervisorDisplayName(c))}</td>`;
        case 'status': {
            const statusBadge = c.status
                ? `<span class="badge badge-${c.status.toLowerCase().replace(/\s+/g, '_')}">${esc(c.status)}</span>`
                : '—';
            return `<td>${statusBadge}</td>`;
        }
        case 'sumPoints':
            return `<td>${c.sumPoints !== null && c.sumPoints !== undefined ? c.sumPoints : '—'}</td>`;
        case 'startedAt':
            return `<td>${formatUnixDateTime(c.startedAt)}</td>`;
        case 'completedAt':
            return `<td>${formatUnixDateTime(c.completedAt)}</td>`;
        case 'submittedAt':
            return `<td>${formatUnixDateTime(c.submittedAt)}</td>`;
        case 'submissionID':
            return `<td>${c.submissionID ? esc(c.submissionID) : '—'}</td>`;
        case 'structureRevision':
            return `<td>${c.structureRevision ?? '—'}</td>`;
        case 'submittedByRole':
            return `<td>${c.submittedByRole ? esc(c.submittedByRole) : '—'}</td>`;
        case 'submittedBy':
            return `<td>${c.submittedBy ? esc(c.submittedBy) : '—'}</td>`;
        default:
            return '<td>—</td>';
    }
}

function renderTableRows() {
    const body = document.getElementById('resultsBody');
    let rows = getFilteredRows();

    // Sort (preserve client grouping when sorting by client in all-versions mode)
    if (sortCol) {
        rows = [...rows].sort((a, b) => {
            let va = getCellValue(a, sortCol);
            let vb = getCellValue(b, sortCol);
            if (va == null) va = '';
            if (vb == null) vb = '';
            if (typeof va === 'number' && typeof vb === 'number') {
                return sortDir === 'asc' ? va - vb : vb - va;
            }
            const cmp = String(va).localeCompare(String(vb), undefined, { numeric: true });
            return sortDir === 'asc' ? cmp : -cmp;
        });
    }

    const rowLabel = showAllVersions ? 'submission' : 'client';
    document.getElementById('resultCount').textContent = `${rows.length} ${rowLabel}${rows.length === 1 ? '' : 's'}`;

    renderPagination(rows.length);

    if (!rows.length) {
        body.innerHTML = `<tr><td colspan="99" style="text-align:center;color:var(--text-secondary);padding:30px">No results found</td></tr>`;
        return;
    }

    const totalPages = Math.max(1, Math.ceil(rows.length / PAGE_SIZE));
    if (page >= totalPages) page = totalPages - 1;
    const pageRows = rows.slice(page * PAGE_SIZE, (page + 1) * PAGE_SIZE);

    const optionMap = {};
    questionsDef.forEach(q => {
        (q.answerOptions || []).forEach(o => {
            optionMap[o.answerOptionID] = o.defaultText;
        });
    });

    const fixedCols = getTableFixedColumns();
    let prevClientCode = null;
    body.innerHTML = pageRows.map(c => {
        const groupStart = showAllVersions && c.clientCode !== prevClientCode;
        prevClientCode = c.clientCode;

        const questionCells = resultColumns.map(col => {
            const ans = c.answers && c.answers[col.questionID];
            const val = resultColumnCellValue(col, ans, optionMap);
            if (val == null || val === '') return '<td>—</td>';
            return `<td>${esc(String(val))}</td>`;
        }).join('');

        const fixedCells = fixedCols.map(col => fixedColumnCellHtml(c, col, { groupStart })).join('');

        return `<tr class="${groupStart ? 'client-group-row' : ''}">${fixedCells}${questionCells}</tr>`;
    }).join('');
}

function getCellValue(client, key) {
    if (key === 'clientCode') return client.clientCode;
    if (key === 'version') return client.version;
    if (key === 'coachUsername') return coachDisplayName(client);
    if (key === 'supervisorUsername') return supervisorDisplayName(client);
    if (key === 'status') return client.status;
    if (key === 'sumPoints') return client.sumPoints;
    if (key === 'programCycleNumber') return client.programCycleNumber;
    if (key === 'programSessionNumber') return client.programSessionNumber;
    if (key === 'programSessionID') return client.programSessionID;
    if (key === 'startedAt') return client.startedAt;
    if (key === 'completedAt') return client.completedAt;
    if (key === 'submittedAt') return client.submittedAt;
    if (key === 'submissionID') return client.submissionID;
    if (key === 'structureRevision') return client.structureRevision;
    if (key === 'submittedByRole') return client.submittedByRole;
    if (key === 'submittedBy') return client.submittedBy;
    const col = resultColumns.find(c => c.key === key);
    if (col) {
        const ans = client.answers && client.answers[col.questionID];
        const optionMap = {};
        questionsDef.forEach(q => {
            (q.answerOptions || []).forEach(o => {
                optionMap[o.answerOptionID] = o.defaultText;
            });
        });
        return resultColumnCellValue(col, ans, optionMap);
    }
    return null;
}

async function exportCSV() {
    const versionParam = showAllVersions ? '&allVersions=1' : '';
    const btn = document.getElementById('exportCsvLink');
    const prev = btn.textContent;
    btn.disabled = true;
    btn.textContent = 'Downloading…';
    try {
        const res = await apiDownloadFetch(apiUrl(`export?questionnaireID=${encodeURIComponent(questionnaireId)}${versionParam}`));
        if (!res.ok) {
            const err = await res.json().catch(() => ({}));
            throw new Error(err.error?.message || err.error || 'Export failed');
        }
        const blob = await res.blob();
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        const stamp = new Date().toISOString().slice(0, 10);
        a.download = showAllVersions
            ? `${questionnaireMeta.name}_all_versions_${stamp}.csv`
            : `${questionnaireMeta.name}_v${questionnaireMeta.version}_results.csv`;
        a.click();
        URL.revokeObjectURL(url);
        showToast('CSV exported', 'success');
    } catch (e) {
        showToast(e.message, 'error');
    } finally {
        btn.disabled = false;
        btn.textContent = prev;
    }
}

function esc(s) {
    const d = document.createElement('div');
    d.textContent = s ?? '';
    return d.innerHTML;
}
