import { apiGet, apiPost, apiPut, apiDelete, apiDownloadFetch, apiUrl } from '../api.js';
import { canEdit, pageHeaderHTML, showToast } from '../app.js';
import { confirmAction } from '../confirm-modal.js';
import {
    SOURCE_LANG,
    normalizeEntry,
    translationFor,
    targetLanguages,
    sourceLanguageLabel,
    translationListHeaderHTML,
    buildTranslationGroups,
    renderCollapsibleGroupedTranslationsHTML,
    flattenAllQuestionnaires,
    countMissing,
    sectionEntries,
    escHtml as esc,
} from '../translations-helpers.js';

const STORAGE_LANG = 'qdb_trans_lang';
const STORAGE_SCOPE = 'qdb_trans_scope';
const STORAGE_SHOW = 'qdb_trans_show_mode';

let transData = null;
let allEntries = [];
let selectedLang = '';
let selectedScope = '';
/** @type {'missing' | 'all' | 'complete'} */
let showMode = 'missing';
let saveTimers = {};
let savesInFlight = 0;

export async function translationsPage() {
    const app = document.getElementById('app');
    app.innerHTML = `
        ${pageHeaderHTML('Translations', '<span id="transHeaderActions"></span>')}
        <div id="transPageRoot"><div class="spinner"></div></div>
    `;

    if (canEdit()) {
        document.getElementById('transHeaderActions').innerHTML = `
            <input type="file" id="importTransBundleFile" accept=".json,application/json" hidden>
            <button type="button" class="btn" id="importTransBundleBtn">Import translations</button>
            <button type="button" class="btn btn-primary" id="exportTransBundleBtn">Export translations</button>
        `;
        bindTranslationBundleActions();
    }

    try {
        renderShell();
        await loadTranslations();
    } catch (e) {
        document.getElementById('transPageRoot').innerHTML =
            `<p class="error-text" style="padding:16px">${esc(e.message)}</p>`;
    }
}

function renderShell() {
    document.getElementById('transPageRoot').innerHTML = `
        <div class="card trans-page">
            <div class="trans-controls">
                <label class="trans-control">
                    <span>Translate into</span>
                    <select id="transLangSelect" class="trans-select" disabled>
                        <option value="">—</option>
                    </select>
                </label>
            </div>

            <details class="trans-lang-panel">
                <summary>More languages</summary>
                <div id="transLangPanel"><span class="text-muted">Loading…</span></div>
            </details>

            <div class="trans-toolbar">
                <label class="trans-control trans-toolbar-field">
                    <span>Content</span>
                    <select id="transScopeSelect" class="trans-select" disabled>
                        <option value="">Loading…</option>
                    </select>
                </label>
                <label class="trans-control trans-toolbar-field">
                    <span>Show</span>
                    <select id="transShowMode" class="trans-select trans-type-select" disabled>
                        <option value="missing">Missing only</option>
                        <option value="all">All</option>
                        <option value="complete">Complete only</option>
                    </select>
                </label>
                <input type="search" id="transFilter" class="trans-search-input" placeholder="Search in scope…" disabled>
                <select id="transTypeFilter" class="trans-select trans-type-select" disabled>
                    <option value="">All types</option>
                    <option value="app_string">App strings</option>
                    <option value="string">Questionnaire UI strings</option>
                    <option value="question">Questions</option>
                    <option value="answer_option">Answer options</option>
                </select>
            </div>

            <div id="transListArea"><div class="spinner"></div></div>
        </div>
    `;
}

function pickDefaultTargetLang(languages) {
    const targets = targetLanguages(languages);
    if (!targets.length) return '';
    const stored = localStorage.getItem(STORAGE_LANG);
    if (stored && targets.some(l => l.languageCode === stored)) {
        return stored;
    }
    if (selectedLang && targets.some(l => l.languageCode === selectedLang)) {
        return selectedLang;
    }
    return targets[0].languageCode;
}

function pickDefaultShowMode() {
    const stored = localStorage.getItem(STORAGE_SHOW);
    if (stored === 'missing' || stored === 'all' || stored === 'complete') {
        return stored;
    }
    return 'missing';
}

function pickDefaultScope(sections, entries, lang) {
    const stored = localStorage.getItem(STORAGE_SCOPE);
    if (stored === '__all__' || sections.some(s => s.questionnaireID === stored)) {
        return stored;
    }
    for (const sec of sections) {
        const slice = sectionEntries(entries, sec);
        if (countMissing(slice, lang) > 0) {
            return sec.questionnaireID;
        }
    }
    return sections[0]?.questionnaireID || '__app__';
}

function scopeLabel(sec, entries, lang) {
    const slice = sectionEntries(entries, sec);
    const missing = countMissing(slice, lang);
    const suffix = missing ? ` (${missing} missing)` : ' (complete)';
    return `${sec.name}${suffix}`;
}

function scopedSections() {
    const sections = transData?.sections || [];
    if (!selectedScope || selectedScope === '__all__') {
        return sections;
    }
    return sections.filter(s => s.questionnaireID === selectedScope);
}

function entriesInScope() {
    const sections = scopedSections();
    const out = [];
    for (const sec of sections) {
        out.push(...sectionEntries(allEntries, sec));
    }
    return out;
}

function setSaveStatus(state) {
    const el = document.getElementById('transSaveStatus');
    if (!el) return;
    el.dataset.state = state;
    if (state === 'saving') {
        el.textContent = 'Saving…';
    } else if (state === 'error') {
        el.textContent = 'Save failed';
    } else {
        el.textContent = 'All changes saved';
    }
}

async function ensureGermanLanguage() {
    try {
        await apiPut('translations.php', { type: 'language', languageCode: SOURCE_LANG, name: 'German' });
    } catch (_) { /* already exists */ }
}

async function loadTranslations() {
    const listArea = document.getElementById('transListArea');
    const langSelect = document.getElementById('transLangSelect');
    const filter = document.getElementById('transFilter');
    const typeFilter = document.getElementById('transTypeFilter');

    if (listArea) listArea.innerHTML = '<div class="spinner"></div>';
    saveTimers = {};

    try {
        await ensureGermanLanguage();
        const data = await apiGet('translations.php?all=1');
        transData = data;
        const languages = transData.languages || [];
        const questionnaires = transData.questionnaires || [];

        const flat = flattenAllQuestionnaires(questionnaires, data.appStrings || []);
        allEntries = flat.allEntries;
        transData.sections = flat.sections;

        selectedLang = pickDefaultTargetLang(languages);
        showMode = pickDefaultShowMode();
        selectedScope = pickDefaultScope(flat.sections, allEntries, selectedLang);

        if (langSelect) {
            const targets = targetLanguages(languages);
            langSelect.disabled = !targets.length;
            langSelect.innerHTML = targets.length
                ? targets.map(l => {
                    const label = l.name ? `${l.name} (${l.languageCode})` : l.languageCode;
                    return `<option value="${esc(l.languageCode)}" ${l.languageCode === selectedLang ? 'selected' : ''}>${esc(label)}</option>`;
                }).join('')
                : '<option value="">Add a language below</option>';
            langSelect.onchange = () => {
                selectedLang = langSelect.value;
                localStorage.setItem(STORAGE_LANG, selectedLang);
                populateScopeSelect();
                renderEntryList();
            };
        }

        const scopeSelect = document.getElementById('transScopeSelect');
        const showSelect = document.getElementById('transShowMode');
        if (scopeSelect) {
            scopeSelect.disabled = false;
            populateScopeSelect();
            scopeSelect.onchange = () => {
                selectedScope = scopeSelect.value;
                localStorage.setItem(STORAGE_SCOPE, selectedScope);
                renderEntryList();
            };
        }
        if (showSelect) {
            showSelect.disabled = false;
            showSelect.value = showMode;
            showSelect.onchange = () => {
                showMode = showSelect.value;
                localStorage.setItem(STORAGE_SHOW, showMode);
                applyFilters();
            };
        }

        if (filter) filter.disabled = false;
        if (typeFilter) typeFilter.disabled = false;

        renderLanguagePanel(languages);
        renderEntryList();
        bindFilters();
        setSaveStatus('saved');
    } catch (e) {
        if (listArea) listArea.innerHTML = `<p class="error-text">${esc(e.message)}</p>`;
        showToast(e.message, 'error');
    }
}

function renderLanguagePanel(languages) {
    const panel = document.getElementById('transLangPanel');
    if (!panel) return;

    const others = targetLanguages(languages);

    panel.innerHTML = `
        <p class="text-muted" style="font-size:.85rem;margin:0 0 10px">
            German source text is edited in the questionnaire editor. Add other languages here.
        </p>
        <div class="lang-chips">
            <span class="lang-chip lang-chip-fixed">
                <strong>DE</strong>
                <span class="lang-chip-name">German (source)</span>
            </span>
            ${others.map(l => `
                <span class="lang-chip">
                    <strong>${esc(l.languageCode.toUpperCase())}</strong>
                    ${l.name ? `<span class="lang-chip-name">${esc(l.name)}</span>` : ''}
                    <button type="button" class="lang-chip-remove" data-lc="${esc(l.languageCode)}" title="Remove language">&times;</button>
                </span>
            `).join('')}
        </div>
        <div class="lang-add-row">
            <input type="text" id="newLangCode" placeholder="Code (en)" class="lang-add-code" maxlength="8">
            <input type="text" id="newLangName" placeholder="Name (English)" class="lang-add-name">
            <button type="button" class="btn btn-sm btn-primary" id="addLangBtn">Add</button>
        </div>
    `;

    document.getElementById('addLangBtn')?.addEventListener('click', async () => {
        const code = document.getElementById('newLangCode').value.trim().toLowerCase();
        const name = document.getElementById('newLangName').value.trim();
        if (!code) { showToast('Language code is required', 'error'); return; }
        if (code === SOURCE_LANG) {
            showToast('German (de) is always available as the source language', 'error');
            return;
        }
        if (languages.some(l => l.languageCode === code)) {
            showToast('Language already exists', 'error');
            return;
        }
        try {
            await apiPut('translations.php', { type: 'language', languageCode: code, name });
            showToast(`Language "${code}" added`, 'success');
            selectedLang = code;
            await loadTranslations();
        } catch (e) {
            showToast(e.message, 'error');
        }
    });

    panel.querySelectorAll('.lang-chip-remove').forEach(btn => {
        btn.addEventListener('click', async () => {
            const lc = btn.dataset.lc;
            if (!(await confirmAction({
                title: 'Remove language',
                message: `Remove "${lc}" and all its translations?`,
                confirmLabel: 'Remove',
                variant: 'danger',
            }))) return;
            try {
                await apiDelete('translations.php', { type: 'language', languageCode: lc });
                showToast(`Language "${lc}" removed`, 'success');
                if (selectedLang === lc) selectedLang = '';
                await loadTranslations();
            } catch (e) {
                showToast(e.message, 'error');
            }
        });
    });
}

function populateScopeSelect() {
    const scopeSelect = document.getElementById('transScopeSelect');
    if (!scopeSelect || !transData) return;

    const sections = transData.sections || [];
    const options = sections.map(sec =>
        `<option value="${esc(sec.questionnaireID)}"${sec.questionnaireID === selectedScope ? ' selected' : ''}>${esc(scopeLabel(sec, allEntries, selectedLang))}</option>`
    );
    options.push(`<option value="__all__"${selectedScope === '__all__' ? ' selected' : ''}>All content</option>`);

    scopeSelect.innerHTML = options.join('');
    if (!selectedScope || (selectedScope !== '__all__' && !sections.some(s => s.questionnaireID === selectedScope))) {
        selectedScope = pickDefaultScope(sections, allEntries, selectedLang);
        scopeSelect.value = selectedScope;
        localStorage.setItem(STORAGE_SCOPE, selectedScope);
    }
}

function renderEntryList() {
    const listArea = document.getElementById('transListArea');
    if (!listArea || !transData) return;

    const languages = transData.languages || [];
    const targets = targetLanguages(languages);
    const sections = scopedSections();

    if (!targets.length) {
        listArea.innerHTML = `
            <p class="text-muted trans-hint">Add at least one language under <strong>More languages</strong> to translate into.</p>`;
        return;
    }

    if (!selectedLang) {
        listArea.innerHTML = `<p class="text-muted trans-hint">Choose a language above.</p>`;
        return;
    }

    if (!transData.sections?.length) {
        listArea.innerHTML = `
            <p class="text-muted trans-hint">No translatable content yet. Add questionnaires and questions in the editor first.</p>`;
        return;
    }

    const sourceLabel = sourceLanguageLabel(languages);
    const langLabel = targets.find(l => l.languageCode === selectedLang)?.name || selectedLang.toUpperCase();
    const scopeEntries = entriesInScope();
    const missingCount = countMissing(scopeEntries, selectedLang);
    const pct = scopeEntries.length
        ? Math.round(((scopeEntries.length - missingCount) / scopeEntries.length) * 100)
        : 0;

    const headerOnce = translationListHeaderHTML(langLabel, sourceLabel);
    const useQnDetails = selectedScope === '__all__';

    const sectionsHtml = sections.map(sec => {
        const entries = sectionEntries(allEntries, sec);
        const groups = buildTranslationGroups(entries, selectedLang, sec.startIdx);
        const secMissing = countMissing(entries, selectedLang);
        const inner = renderCollapsibleGroupedTranslationsHTML(groups, selectedLang, sourceLabel, true, {
            openGroupsWithMissing: selectedScope !== '__all__',
        });

        if (useQnDetails) {
            const open = secMissing > 0 && sections.filter(s =>
                countMissing(sectionEntries(allEntries, s), selectedLang) > 0
            )[0]?.questionnaireID === sec.questionnaireID;
            const summary = secMissing
                ? `${sec.name} · ${secMissing} missing`
                : `${sec.name} · complete`;
            return `
                <details class="trans-qn-section"${open ? ' open' : ''} data-qn="${esc(sec.questionnaireID)}">
                    <summary class="trans-qn-summary">${esc(summary)}</summary>
                    ${inner}
                </details>`;
        }

        return `<div class="trans-scope-block" data-qn="${esc(sec.questionnaireID)}">${inner}</div>`;
    }).join('');

    listArea.innerHTML = `
        <div class="trans-top-bar">
            <div class="trans-top-stats">
                <span id="transVisibleCount">${missingCount ? `${missingCount} missing · ` : ''}${scopeEntries.length} in scope</span>
                <span class="trans-stats-progress">
                    <span class="trans-progress-bar"><span class="trans-progress-fill" style="width:${pct}%"></span></span>
                    <span class="trans-progress-label">${pct}% in ${esc(selectedLang.toUpperCase())}</span>
                </span>
            </div>
            <div class="trans-top-actions">
                <span id="transSaveStatus" class="trans-save-status" data-state="saved">All changes saved</span>
                <button type="button" class="btn btn-sm" id="transJumpMissingBtn">Jump to next missing</button>
            </div>
        </div>
        <div class="trans-sheet">
            ${headerOnce}
            <div id="transGroupedRoot" class="trans-sheet-body${useQnDetails ? ' trans-sheet-body-stack' : ''}">${sectionsHtml}</div>
        </div>
    `;

    document.getElementById('transJumpMissingBtn')?.addEventListener('click', jumpToNextMissing);

    bindEntryEditing(allEntries);
    applyFilters();
}

function openAncestors(el) {
    let node = el;
    while (node) {
        if (node.tagName === 'DETAILS') node.open = true;
        node = node.parentElement;
    }
}

function jumpToNextMissing() {
    const rows = [...document.querySelectorAll('#transGroupedRoot .trans-list-item')]
        .filter(r => !r.classList.contains('trans-row-hidden') && r.dataset.missing === '1');
    if (!rows.length) {
        showToast(showMode === 'missing'
            ? 'All translations in this scope are complete'
            : 'No missing translations in view', 'info');
        return;
    }

    const activeRow = document.activeElement?.closest?.('.trans-list-item');
    let start = 0;
    if (activeRow) {
        const idx = rows.indexOf(activeRow);
        if (idx >= 0) start = idx + 1;
    }
    const target = rows[start] || rows[0];
    openAncestors(target);
    const inp = target.querySelector('[data-field="translation"]');
    inp?.focus({ preventScroll: false });
    target.scrollIntoView({ behavior: 'smooth', block: 'center' });
}

function bindEntryEditing(entries) {
    document.querySelectorAll('#transGroupedRoot .trans-cell-input').forEach(inp => {
        inp.addEventListener('input', () => {
            const idx = parseInt(inp.dataset.idx, 10);
            const entry = entries[idx];
            if (!entry) return;

            const isGerman = inp.dataset.field === 'german';
            if (isGerman) {
                entry.germanText = inp.value;
                if (!entry.translations || typeof entry.translations !== 'object') entry.translations = {};
                entry.translations[SOURCE_LANG] = inp.value;
            } else {
                if (!entry.translations || typeof entry.translations !== 'object') entry.translations = {};
                entry.translations[selectedLang] = inp.value;
            }

            if (!isGerman) {
                const missing = !inp.value.trim();
                inp.classList.toggle('trans-input-missing', missing);
                const row = inp.closest('.trans-list-item');
                if (row) {
                    row.classList.toggle('trans-list-item-missing', missing);
                    row.dataset.missing = missing ? '1' : '0';
                }
            }

            const timerKey = isGerman ? `${idx}_de` : `${idx}_${selectedLang}`;
            clearTimeout(saveTimers[timerKey]);
            saveTimers[timerKey] = setTimeout(() => saveTranslation(entry, inp, isGerman), 500);
            setSaveStatus('saving');
        });
    });
}

async function saveTranslation(entry, inp, isGerman = false) {
    savesInFlight++;
    setSaveStatus('saving');
    try {
        await apiPut('translations.php', {
            type: entry.type,
            id: entry.entityId,
            languageCode: isGerman ? SOURCE_LANG : selectedLang,
            text: inp.value,
        });
        inp.classList.add('save-flash');
        setTimeout(() => inp.classList.remove('save-flash'), 400);
        updateProgress();
    } catch (e) {
        setSaveStatus('error');
        showToast(e.message, 'error');
    } finally {
        savesInFlight = Math.max(0, savesInFlight - 1);
        if (savesInFlight === 0) {
            setSaveStatus('saved');
            populateScopeSelect();
        }
    }
}

function updateProgress() {
    const scopeEntries = entriesInScope();
    const missing = countMissing(scopeEntries, selectedLang);
    const pct = scopeEntries.length
        ? Math.round(((scopeEntries.length - missing) / scopeEntries.length) * 100)
        : 0;
    const fill = document.querySelector('.trans-progress-fill');
    if (fill) fill.style.width = `${pct}%`;
    const label = document.querySelector('.trans-progress-label');
    if (label) label.textContent = `${pct}% in ${selectedLang.toUpperCase()}`;
    if (!document.getElementById('transFilter')?.value && !document.getElementById('transTypeFilter')?.value) {
        updateVisibleCountSummary();
    }
}

function updateVisibleCountSummary(visible = null, visibleMissing = null) {
    const countEl = document.getElementById('transVisibleCount');
    if (!countEl) return;
    const scopeEntries = entriesInScope();
    const text = document.getElementById('transFilter')?.value || '';
    const type = document.getElementById('transTypeFilter')?.value || '';
    if (text || type || showMode !== 'missing') {
        if (visible != null) {
            countEl.textContent = `Showing ${visible}${visibleMissing ? ` (${visibleMissing} missing)` : ''}`;
        }
        return;
    }
    const missing = countMissing(scopeEntries, selectedLang);
    countEl.textContent = `${missing ? `${missing} missing · ` : ''}${scopeEntries.length} in scope`;
}

let filtersBound = false;

function bindFilters() {
    if (filtersBound) {
        applyFilters();
        return;
    }
    filtersBound = true;

    document.getElementById('transFilter')?.addEventListener('input', applyFilters);
    document.getElementById('transTypeFilter')?.addEventListener('change', applyFilters);
}

function applyFilters() {
    const text = (document.getElementById('transFilter')?.value || '').toLowerCase();
    const type = document.getElementById('transTypeFilter')?.value || '';
    const items = document.querySelectorAll('#transGroupedRoot .trans-list-item');
    let visible = 0;
    let visibleMissing = 0;

    items.forEach(row => {
        const key = row.dataset.key?.toLowerCase() || '';
        const label = row.dataset.label?.toLowerCase()
            || row.querySelector('.trans-key-text')?.textContent?.toLowerCase() || '';
        const rowType = row.dataset.type || '';
        const german = row.querySelector('.trans-source-text')?.textContent?.toLowerCase()
            || row.querySelector('[data-field="german"]')?.value?.toLowerCase() || '';
        const val = row.querySelector('[data-field="translation"]')?.value?.toLowerCase() || '';
        const isMissing = row.dataset.missing === '1';
        let show = (!type || rowType === type) &&
            (!text || key.includes(text) || label.includes(text) || german.includes(text) || val.includes(text));
        if (showMode === 'missing' && !isMissing) show = false;
        if (showMode === 'complete' && isMissing) show = false;
        row.classList.toggle('trans-row-hidden', !show);
        if (show) {
            visible++;
            if (row.dataset.missing === '1') visibleMissing++;
        }
    });

    document.querySelectorAll('#transGroupedRoot .trans-group-details').forEach(group => {
        const rows = group.querySelectorAll('.trans-list-item');
        const anyVisible = [...rows].some(r => !r.classList.contains('trans-row-hidden'));
        group.classList.toggle('trans-group-hidden', !anyVisible);
    });

    document.querySelectorAll('#transGroupedRoot .trans-scope-block, #transGroupedRoot .trans-qn-section').forEach(block => {
        const anyVisible = [...block.querySelectorAll('.trans-list-item')].some(r => !r.classList.contains('trans-row-hidden'));
        block.classList.toggle('trans-qn-hidden', !anyVisible);
    });

    const emptyEl = document.getElementById('transEmptyHint');
    if (emptyEl) emptyEl.remove();
    if (visible === 0 && items.length > 0) {
        const root = document.getElementById('transGroupedRoot');
        if (root) {
            const hint = document.createElement('p');
            hint.id = 'transEmptyHint';
            hint.className = 'text-muted trans-hint trans-empty-hint';
            hint.textContent = showMode === 'missing'
                ? 'All translations in this scope are complete for the selected language.'
                : 'No rows match the current filters.';
            root.insertAdjacentElement('afterend', hint);
        }
    }

    updateVisibleCountSummary(visible, visibleMissing);
}

function bindTranslationBundleActions() {
    const fileInput = document.getElementById('importTransBundleFile');
    const importBtn = document.getElementById('importTransBundleBtn');
    const exportBtn = document.getElementById('exportTransBundleBtn');
    if (!fileInput || !importBtn || !exportBtn) return;

    exportBtn.addEventListener('click', async () => {
        exportBtn.disabled = true;
        const prev = exportBtn.textContent;
        exportBtn.textContent = 'Preparing…';
        try {
            const res = await apiDownloadFetch(apiUrl('translations?exportBundle=1'));
            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 = `translations_bundle_${stamp}.json`;
            a.click();
            URL.revokeObjectURL(url);
            showToast('Translations bundle downloaded', 'success');
        } catch (e) {
            showToast(e.message, 'error');
        } finally {
            exportBtn.disabled = false;
            exportBtn.textContent = prev;
        }
    });

    importBtn.addEventListener('click', () => fileInput.click());

    fileInput.addEventListener('change', async () => {
        const file = fileInput.files?.[0];
        fileInput.value = '';
        if (!file) return;

        let bundle;
        try {
            bundle = JSON.parse(await file.text());
        } catch {
            showToast('Invalid JSON file', 'error');
            return;
        }

        if (!bundle?.entries || !Array.isArray(bundle.entries)) {
            showToast('Not a translations bundle (missing entries array)', 'error');
            return;
        }

        const count = bundle.entries.length;
        if (!(await confirmAction({
            title: 'Import translations',
            message: `Import translations for ${count} entries from this file?`,
            confirmLabel: 'Import',
        }))) return;

        importBtn.disabled = true;
        const prev = importBtn.textContent;
        importBtn.textContent = 'Importing…';
        try {
            const result = await apiPost('translations.php', {
                action: 'importBundle',
                bundle,
            });
            const imported = result.imported ?? 0;
            const skipped = result.skipped ?? 0;
            let msg = `Imported ${imported} translation(s)`;
            if (skipped) msg += ` (${skipped} skipped)`;
            showToast(msg, 'success');
            await loadTranslations();
        } catch (e) {
            showToast(e.message, 'error');
        } finally {
            importBtn.disabled = false;
            importBtn.textContent = prev;
        }
    });
}
