import './echo.js';

const app = window.quizApp;
const state = {
    participants: [...(app.participants || [])],
    topThree: [...(app.topThree || [])],
    overall: [...(app.overall || [])],
    currentQuestion: app.state?.current_question || null,
    questionEndsAt: app.state?.current_question_ends_at || null,
    status: app.state?.status || 'waiting',
    autoNextTimer: null,
    countdownInterval: null,
};

const $ = (id) => document.getElementById(id);
let csrf = app.csrf || document.querySelector('meta[name="csrf-token"]')?.content || '';

function setCsrf(token) {
    if (!token) return;

    csrf = token;
    app.csrf = token;

    const meta = document.querySelector('meta[name="csrf-token"]');
    if (meta) meta.setAttribute('content', token);
}

function csrfToken() {
    return csrf || document.querySelector('meta[name="csrf-token"]')?.content || '';
}

async function refreshCsrf() {
    if (!app.csrfUrl) {
        throw new Error('Session expired. Please refresh the page and try again.');
    }

    const response = await fetch(app.csrfUrl, {
        headers: { 'Accept': 'application/json' },
        credentials: 'same-origin',
    });
    const data = await response.json().catch(() => ({}));

    if (!response.ok || !data.token) {
        throw new Error(data.message || 'Session expired. Please refresh the page and try again.');
    }

    setCsrf(data.token);
    return data.token;
}

async function post(url, payload = {}, retry = true) {
    const token = csrfToken();
    const response = await fetch(url, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'X-CSRF-TOKEN': token,
        },
        credentials: 'same-origin',
        body: JSON.stringify({ ...payload, _token: token }),
    });
    const data = await response.json().catch(() => ({}));

    if (response.status === 419 && retry) {
        await refreshCsrf();
        return post(url, payload, false);
    }

    if (!response.ok) throw new Error(data.message || 'Request failed');
    return data;
}

function renderStatus() {
    $('statusPill').textContent = state.status.toUpperCase();
    const controlsDisabled = app.canControl === false || state.status === 'finished';
    if ($('startBtn')) $('startBtn').disabled = controlsDisabled;
    if ($('nextBtn')) $('nextBtn').disabled = controlsDisabled;
}

function renderParticipants() {
    $('participantCount').textContent = state.participants.length;
    const list = $('participantList');
    list.innerHTML = '';

    if (!state.participants.length) {
        list.innerHTML = '<li class="empty-state">No participants yet.</li>';
        return;
    }

    state.participants.forEach((participant, index) => {
        const li = document.createElement('li');
        li.className = 'participant-item';
        li.innerHTML = `
            <span class="participant-index">${index + 1}</span>
            <span class="participant-avatar" aria-hidden="true">${escapeHtml((participant.name || 'A').charAt(0))}</span>
            <span>${escapeHtml(participant.name)}</span>
            <strong class="score-pill">${participant.score || 0} pts</strong>
        `;
        list.appendChild(li);
    });
}

function syncParticipantScores(overall = state.overall) {
    if (!overall.length) return;

    const scores = new Map(overall.map((item) => [item.name, item.score]));
    state.participants = state.participants.map((participant) => (
        scores.has(participant.name)
            ? { ...participant, score: scores.get(participant.name) }
            : participant
    ));
}

function renderQuestion(question = state.currentQuestion) {
    const title = $('questionTitle');
    const options = $('questionOptions');
    const card = title.closest('.question-card');
    card?.classList.toggle('is-finished', state.status === 'finished' && !question);

    if (!question) {
        if (state.status === 'finished') {
            title.innerHTML = `
                <span class="finished-mark" aria-hidden="true">&#10003;</span>
                <span>Quiz finished.</span>
                <small>Result saved until reset.</small>
            `;
        } else {
            title.textContent = 'Waiting to start...';
        }
        options.innerHTML = '';
        return;
    }

    title.textContent = `${question.sort_order}. ${question.text}`;
    options.innerHTML = '';
    question.options.forEach((option) => {
        const div = document.createElement('div');
        div.className = 'option-row';
        div.textContent = option.text;
        options.appendChild(div);
    });
}

function renderTopThree(topThree = state.topThree) {
    const isFinished = state.status === 'finished';
    if ($('topThreeLabel')) $('topThreeLabel').textContent = isFinished ? 'Final Result' : 'Fastest Correct Answers';
    if ($('topThreeTitle')) $('topThreeTitle').textContent = isFinished ? 'Final Top 3' : 'Live Top 3';

    const byRank = new Map(topThree.map((item) => [item.rank, item]));
    const second = byRank.get(2);
    const first = byRank.get(1);
    const third = byRank.get(3);

    $('topThree').innerHTML = `
        ${podiumBox(second, 'second', '2nd')}
        ${podiumBox(first, 'first', '1st')}
        ${podiumBox(third, 'third', '3rd')}
    `;
}

function podiumBox(item, cssClass, label) {
    if (!item) {
        return `<div class="podium-box ${cssClass}"><span class="podium-medal">${label}</span><strong>Waiting</strong><small>--</small></div>`;
    }

    const detail = item.response_ms !== undefined && item.response_ms !== null
        ? `${item.response_ms}ms &middot; +${item.score_awarded || 0}`
        : `${item.score ?? item.total_score ?? 0} pts`;

    return `<div class="podium-box ${cssClass} flash"><span class="podium-medal">${label}</span><strong>${escapeHtml(item.name)}</strong><small>${escapeHtml(detail)}</small></div>`;
}

function renderOverall(overall = state.overall) {
    const list = $('overallList');
    list.innerHTML = '';

    if (!overall.length) {
        list.innerHTML = '<li class="empty-state">No score yet.</li>';
        return;
    }

    overall.forEach((item) => {
        const li = document.createElement('li');
        li.innerHTML = `<span>${item.rank}. ${escapeHtml(item.name)}</span><strong class="score-pill">${item.score} pts</strong>`;
        list.appendChild(li);
    });
}

function startCountdown(endsAt) {
    state.questionEndsAt = endsAt;
    clearInterval(state.countdownInterval);
    clearTimeout(state.autoNextTimer);

    if (!endsAt) {
        $('timer').textContent = '--';
        return;
    }

    const tick = () => {
        const remaining = Math.max(0, Math.ceil((new Date(endsAt).getTime() - Date.now()) / 1000));
        $('timer').textContent = `${remaining}s`;
        if (remaining <= 0) {
            clearInterval(state.countdownInterval);
        }
    };

    tick();
    state.countdownInterval = setInterval(tick, 250);

    const ms = Math.max(0, new Date(endsAt).getTime() - Date.now() + 900);
    state.autoNextTimer = setTimeout(() => {
        post(app.routes.next).catch(console.error);
    }, ms);
}

function applyQuestionPayload(payload) {
    state.status = payload.quiz.status;
    state.currentQuestion = payload.question;
    state.topThree = [];
    renderStatus();
    renderQuestion(payload.question);
    renderTopThree([]);
    startCountdown(payload.question.ends_at);
}

function escapeHtml(value) {
    return String(value || '').replace(/[&<>'"]/g, (char) => ({
        '&': '&amp;',
        '<': '&lt;',
        '>': '&gt;',
        "'": '&#039;',
        '"': '&quot;',
    }[char]));
}

function wireModal({ modalId, openId, closeId, focusId }) {
    const modal = $(modalId);
    const openButton = $(openId);
    const closeButton = $(closeId);

    const open = () => {
        modal.classList.add('is-open');
        modal.setAttribute('aria-hidden', 'false');
        $(focusId)?.focus();
    };

    const close = () => {
        modal.classList.remove('is-open');
        modal.setAttribute('aria-hidden', 'true');
        openButton?.focus();
    };

    openButton?.addEventListener('click', open);
    closeButton?.addEventListener('click', close);
    modal?.addEventListener('click', (event) => {
        if (event.target === modal) close();
    });

    return { modal, open, close };
}

const importModal = wireModal({
    modalId: 'importModal',
    openId: 'openImportModal',
    closeId: 'closeImportModal',
    focusId: 'import_question_text',
});

const testModal = wireModal({
    modalId: 'testModal',
    openId: 'openTestModal',
    closeId: 'closeTestModal',
    focusId: 'test_title',
});

$('openImportModalNotice')?.addEventListener('click', () => importModal.open());
$('openQuestionsNav')?.addEventListener('click', () => importModal.open());
$('openSettingsNav')?.addEventListener('click', () => testModal.open());

document.addEventListener('keydown', (event) => {
    if (event.key !== 'Escape') return;

    if (importModal.modal?.classList.contains('is-open')) {
        importModal.close();
    }

    if (testModal.modal?.classList.contains('is-open')) {
        testModal.close();
    }
});

document.querySelectorAll('input[name="correct_option"]').forEach((input) => {
    input.addEventListener('change', () => {
        const label = $('correctChoiceLabel');
        if (label) label.textContent = input.value;
    });
});

$('startBtn').addEventListener('click', () => post(app.routes.start).catch(alert));
$('nextBtn').addEventListener('click', () => post(app.routes.next).catch(alert));
$('resetBtn').addEventListener('click', () => {
    if (!confirm('Reset quiz, participants, answers, and scores?')) return;
    post(app.routes.reset)
        .then(() => window.location.reload())
        .catch(alert);
});

window.Echo.channel(`quiz.${app.quizUuid}`)
    .listen('.participant.joined', (event) => {
        const exists = state.participants.some((item) => item.session_uuid === event.participant.session_uuid);
        if (!exists) state.participants.push(event.participant);
        renderParticipants();
    })
    .listen('.quiz.started', (event) => {
        state.status = event.quiz.status;
        state.topThree = [];
        state.overall = [];
        state.participants = state.participants.map((participant) => ({ ...participant, score: 0 }));
        renderStatus();
        renderParticipants();
        renderTopThree([]);
        renderOverall([]);
    })
    .listen('.question.started', (event) => applyQuestionPayload(event))
    .listen('.leaderboard.updated', (event) => {
        state.topThree = event.top_three || [];
        state.overall = event.overall || [];
        syncParticipantScores();
        renderParticipants();
        renderTopThree(state.topThree);
        renderOverall(state.overall);
    })
    .listen('.quiz.finished', (event) => {
        state.status = event.quiz.status;
        state.currentQuestion = null;
        state.overall = event.overall || [];
        state.topThree = event.top_three?.length
            ? event.top_three
            : state.overall.slice(0, 3).map((item, index) => ({ ...item, rank: item.rank || index + 1 }));
        syncParticipantScores();
        clearInterval(state.countdownInterval);
        clearTimeout(state.autoNextTimer);
        $('timer').textContent = '--';
        renderStatus();
        renderQuestion(null);
        renderParticipants();
        renderTopThree(state.topThree);
        renderOverall(state.overall);
    })
    .listen('.quiz.reset', () => window.location.reload());

renderStatus();
renderParticipants();
renderQuestion();
renderTopThree();
renderOverall();
startCountdown(state.questionEndsAt);
