import {
    sessionId, setSessionId, setCurrentPersona, currentPersona, dom, setRpgEnabled,
} from './state.js';
import {
    updateQuestPanel, updateAffinityDisplay, updateStatsDisplay, hideStatsDisplay,
} from './chat.js';
import { highlightPersonaBar, personaIndex } from './personas.js';
import { formatSessionDate } from './utils.js';
import { openNewChatWizard } from './newChatWizard.js';

export { openNewChatWizard, initNewChatWizard } from './newChatWizard.js';
export { openChatSettings, initChatSettings } from './chatSettings.js';

function escapeTitle(t) {
    const d = document.createElement('div');
    d.textContent = t;
    return d.innerHTML;
}

export function applySessionUi(session) {
    if (!session) return;
    dom.headerTitle.textContent = session.title || 'Новый чат';
    const rpgOn = !!session.rpg_enabled;
    setRpgEnabled(rpgOn);
    document.getElementById('rpgBadge')?.classList.toggle('hidden', !rpgOn);

    let settings = { quests: true, affinity: true };
    try {
        settings = { ...settings, ...JSON.parse(session.rpg_settings_json || '{}') };
    } catch { /* ignore */ }

    document.getElementById('questPanel')?.classList.toggle('hidden', !rpgOn || !settings.quests);
    if (rpgOn && settings.affinity) {
        updateAffinityDisplay(session.affinity ?? 0);
        dom.affinityDisplay?.classList.remove('hidden');
    } else {
        dom.affinityDisplay?.classList.add('hidden');
    }

    if (rpgOn && settings.stats) {
        try {
            updateStatsDisplay(JSON.parse(session.narrative_stats_json || '{}'));
        } catch {
            hideStatsDisplay();
        }
    } else {
        hideStatsDisplay();
    }

    if (rpgOn && settings.quests) {
        fetch(`/sessions/${session.session_id}/quests`)
            .then(r => r.ok ? r.json() : [])
            .then(q => updateQuestPanel(q))
            .catch(() => {});
    }
}

export async function loadSessions() {
    const res = await fetch('/sessions/');
    const sessions = await res.json();
    dom.sessionList.innerHTML = '';

    sessions.forEach(s => {
        const item = document.createElement('div');
        item.className = 'session-item' + (s.session_id === sessionId ? ' active' : '');
        const personaName = personaIndex.get(s.persona_id)?.name || s.persona_id || 'default';
        const dateStr = formatSessionDate(s.updated_at);
        item.innerHTML = `
            <div class="s-row">
                <div class="s-title" title="Двойной клик — переименовать">${escapeTitle(s.title || 'Новый чат')}</div>
                ${s.rpg_enabled ? '<span class="s-badge">RPG</span>' : ''}
                ${dateStr ? `<span class="s-date">${dateStr}</span>` : ''}
            </div>
            <div class="s-companion">С: ${escapeTitle(personaName)}</div>
            <div class="s-preview">${escapeTitle(s.last_message_preview || '')}</div>
            <div class="s-meta">${s.message_count} сообщ.</div>
            <button class="s-del" type="button">🗑</button>
        `;
        item.addEventListener('click', (e) => {
            if (e.target.closest('.s-del') || item.querySelector('.s-title')?.isContentEditable) return;
            switchSession(s.session_id);
        });
        const titleEl = item.querySelector('.s-title');
        titleEl.addEventListener('dblclick', (e) => {
            e.stopPropagation();
            titleEl.contentEditable = 'true';
            titleEl.focus();
        });
        titleEl.addEventListener('blur', async () => {
            titleEl.contentEditable = 'false';
            const t = titleEl.textContent.trim();
            if (t && t !== (s.title || 'Новый чат')) {
                await fetch(`/sessions/${s.session_id}`, {
                    method: 'PATCH',
                    headers: { 'Content-Type': 'application/json' },
                    body: JSON.stringify({ title: t }),
                });
                if (s.session_id === sessionId) dom.headerTitle.textContent = t;
                loadSessions();
            }
        });
        titleEl.addEventListener('keydown', (e) => {
            if (e.key === 'Enter') { e.preventDefault(); titleEl.blur(); }
        });
        item.querySelector('.s-del').addEventListener('click', async (e) => {
            e.stopPropagation();
            await fetch(`/sessions/${s.session_id}`, { method: 'DELETE' });
            if (s.session_id === sessionId) openNewChatWizard();
            else loadSessions();
        });
        dom.sessionList.appendChild(item);
    });
}

export async function switchSession(id) {
    setSessionId(id);
    const { clearMessages } = await import('./chat.js');
    clearMessages();
    await loadSessions();
    await loadChatHistory(id);
}

export async function loadChatHistory(id) {
    const sessionRes = await fetch(`/sessions/${id}`);
    if (sessionRes.ok) {
        const s = await sessionRes.json();
        if (s.persona_id) {
            setCurrentPersona(s.persona_id);
            highlightPersonaBar(s.persona_id);
        }
        applySessionUi(s);
    }

    try {
        const blobRes = await fetch(`/chat/system/${id}`);
        if (blobRes.ok) {
            _prevBlobSections = {};  // reset on session switch to avoid false highlights
            renderSystemBlob(await blobRes.json());
        }
    } catch { /* ignore */ }

    const { reloadChatFromServer } = await import('./chat.js');
    await reloadChatFromServer(id);
}

export async function initSessions() {
    await loadSessions();
    if (sessionId) {
        const check = await fetch(`/sessions/${sessionId}`);
        if (check.ok) await switchSession(sessionId);
        else openNewChatWizard();
    } else {
        openNewChatWizard();
    }

    dom.systemBlobRefresh?.addEventListener('click', async () => {
        if (!sessionId) return;
        dom.systemBlobRefresh.classList.add('spinning');
        try {
            const res = await fetch(`/chat/system/${sessionId}`);
            if (res.ok) renderSystemBlob(await res.json());
        } finally {
            dom.systemBlobRefresh.classList.remove('spinning');
        }
    });
}

let _prevBlobSections = {};

export function renderSystemBlob(blob) {
    const tryFmt = (str, fallback = '') => {
        try { return JSON.stringify(JSON.parse(str), null, 2); } catch { return str || fallback; }
    };

    const questLines = (blob.quests || []).map(q => {
        const icon = q.status === 'done' ? '✓' : q.status === 'failed' ? '✗' : '◆';
        return `  ${icon} [${q.status}] ${q.title}`;
    }).join('\n');

    const personaLine = blob.persona_id
        ? `[persona] ${blob.persona_name || blob.persona_id} (${blob.persona_id})`
        : '';

    const ctx = blob.context_usage;
    const ctxLine = ctx
        ? `[context] ~${ctx.tokens_est} / ${ctx.max_tokens_est} tokens (${ctx.percent}%) · ${ctx.chars} chars`
        : '';

    const sections = {
        context:         ctxLine,
        persona:         personaLine,
        system_prompt:   blob.system_prompt ? `[system_prompt]\n${blob.system_prompt}` : '',
        status_quo:      blob.status_quo    ? `[status_quo]\n${blob.status_quo}` : '',
        affinity:        blob.affinity != null ? `[affinity] ${blob.affinity}` : '',
        scene:           blob.scene_json && blob.scene_json !== '{}' ? `[scene]\n${tryFmt(blob.scene_json)}` : '',
        stats:           blob.narrative_stats_json && blob.narrative_stats_json !== '{}' ? `[stats]\n${tryFmt(blob.narrative_stats_json)}` : '',
        genre:           blob.genre         ? `[genre] ${blob.genre}` : '',
        rpg_settings:    blob.rpg_settings_json && blob.rpg_settings_json !== '{}' ? `[rpg_settings]\n${tryFmt(blob.rpg_settings_json)}` : '',
        outfit:          `[outfit]\n${tryFmt(blob.outfit_json ?? '[]')}`,
        facts:           blob.facts_json && blob.facts_json !== '[]' ? `[facts]\n${tryFmt(blob.facts_json)}` : '',
        plot_arc:        blob.plot_arc_json && blob.plot_arc_json !== '{}' ? `[plot_arc]\n${tryFmt(blob.plot_arc_json)}` : '',
        quests:          questLines ? `[quests]\n${questLines}` : '',
    };

    const el = dom.systemBlobContent;
    el.innerHTML = '';

    for (const [key, text] of Object.entries(sections)) {
        if (!text) continue;
        const span = document.createElement('span');
        span.textContent = text;
        if (key === 'context' && ctx && ctx.percent > 80) {
            span.className = 'blob-context-warn';
        } else if (_prevBlobSections[key] && _prevBlobSections[key] !== text) {
            span.className = 'blob-changed';
            setTimeout(() => span.classList.remove('blob-changed'), 3000);
        }
        el.appendChild(span);
        el.appendChild(document.createTextNode('\n\n'));
    }

    if (!el.textContent.trim()) el.textContent = '—';
    _prevBlobSections = { ...sections };
}
