import './echo';

const app = window.quizApp;
const state = {
    isPlayable: app.isPlayable !== false,
    currentQuestion: app.state?.current_question || null,
    questionEndsAt: app.state?.current_question_ends_at || null,
    status: app.state?.status || 'waiting',
    topThree: [...(app.topThree || [])],
    answeredQuestionId: 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 postAnswer(optionId, retry = true) {
    const token = csrfToken();
    const response = await fetch(app.answerUrl, {
        method: 'POST',
        headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json',
            'X-CSRF-TOKEN': token,
        },
        credentials: 'same-origin',
        body: JSON.stringify({ option_id: optionId, _token: token }),
    });
    const data = await response.json().catch(() => ({}));

    if (response.status === 419 && retry) {
        await refreshCsrf();
        return postAnswer(optionId, false);
    }

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

function renderStatus() {
    $('playerStatus').textContent = state.isPlayable ? state.status.toUpperCase() : 'INACTIVE';
}

function renderQuestion(question = state.currentQuestion) {
    const title = $('playerQuestion');
    const options = $('playerOptions');
    const waitingHint = $('waitingHint');
    $('answerMessage').textContent = '';

    if (!state.isPlayable) {
        title.textContent = 'This test is currently inactive.';
        if (waitingHint) waitingHint.hidden = true;
        options.innerHTML = '';
        return;
    }

    if (!question) {
        if (waitingHint) waitingHint.hidden = state.status === 'finished';
        title.textContent = state.status === 'finished'
            ? 'Quiz finished. Thank you for participating.'
            : 'Waiting for admin to start the quiz...';
        options.innerHTML = '';
        return;
    }

    if (waitingHint) waitingHint.hidden = true;
    title.textContent = `${question.sort_order}. ${question.text}`;
    options.innerHTML = '';

    question.options.forEach((option) => {
        const button = document.createElement('button');
        button.className = 'answer-button';
        button.textContent = option.text;
        button.type = 'button';
        button.addEventListener('click', () => submitAnswer(button, option.id));
        options.appendChild(button);
    });
}

function submitAnswer(button, optionId) {
    if (!state.currentQuestion || state.answeredQuestionId === state.currentQuestion.id) return;

    state.answeredQuestionId = state.currentQuestion.id;
    document.querySelectorAll('.answer-button').forEach((item) => item.disabled = true);
    button.classList.add('selected');
    $('answerMessage').textContent = 'Answer submitted...';

    postAnswer(optionId)
        .then((data) => {
            $('myScore').textContent = data.total_score;
            $('answerMessage').textContent = data.correct
                ? `Correct. Response: ${data.response_ms}ms. Score: +${data.score_awarded}`
                : 'Incorrect. Score: 0';
            $('answerMessage').className = `answer-message ${data.correct ? 'success' : 'error'}`;
        })
        .catch((error) => {
            $('answerMessage').textContent = error.message;
            $('answerMessage').className = 'answer-message error';
        });
}

function renderTopThree(topThree = state.topThree) {
    const isFinished = state.status === 'finished';
    if ($('playerTopThreeLabel')) $('playerTopThreeLabel').textContent = isFinished ? 'Final Result' : 'Fastest Correct Answers';
    if ($('playerTopThreeTitle')) $('playerTopThreeTitle').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>${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>${label}</span><strong>${escapeHtml(item.name)}</strong><small>${escapeHtml(detail)}</small></div>`;
}

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

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

    const tick = () => {
        const remaining = Math.max(0, Math.ceil((new Date(endsAt).getTime() - Date.now()) / 1000));
        $('playerTimer').textContent = `${remaining}s`;
        if (remaining <= 0) {
            clearInterval(state.countdownInterval);
            document.querySelectorAll('.answer-button').forEach((item) => item.disabled = true);
            if (state.currentQuestion && state.answeredQuestionId !== state.currentQuestion.id) {
                $('answerMessage').textContent = 'Time is over.';
                $('answerMessage').className = 'answer-message error';
            }
        }
    };

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

function applyQuestionPayload(payload) {
    state.status = payload.quiz.status;
    state.currentQuestion = payload.question;
    state.answeredQuestionId = null;
    $('answerMessage').className = 'answer-message';
    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]));
}

window.Echo.channel(`quiz.${app.quizUuid}`)
    .listen('.quiz.started', (event) => {
        state.status = event.quiz.status;
        state.topThree = [];
        renderStatus();
        renderTopThree([]);
    })
    .listen('.question.started', (event) => applyQuestionPayload(event))
    .listen('.leaderboard.updated', (event) => {
        state.topThree = event.top_three || [];
        renderTopThree(state.topThree);
    })
    .listen('.quiz.finished', (event) => {
        state.status = event.quiz.status;
        state.currentQuestion = null;
        state.topThree = event.top_three?.length
            ? event.top_three
            : (event.overall || []).slice(0, 3).map((item, index) => ({ ...item, rank: item.rank || index + 1 }));
        clearInterval(state.countdownInterval);
        renderStatus();
        renderQuestion(null);
        renderTopThree(state.topThree);
    })
    .listen('.quiz.reset', () => {
        window.location.href = app.joinUrl || './join';
    });

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