/** @odoo-module */

import { Component, onMounted, onWillStart, onWillUnmount, useState, useRef } from "@odoo/owl";
import { registry } from "@web/core/registry";

const AUTOSAVE_INTERVAL = 10000;

export class ExamApp extends Component {
    static template = "encoach_exam_session.ExamApp";
    static props = {};

    setup() {
        this.rootRef = useRef("root");
        this.state = useState({
            loading: true,
            examData: null,
            currentSectionIdx: 0,
            currentQuestionIdx: 0,
            answers: {},
            flagged: {},
            timeRemaining: 0,
            totalTimeRemaining: 0,
            submitted: false,
            showReview: false,
            showConfirmSubmit: false,
            submitMessage: "",
        });

        this.timerInterval = null;
        this.autosaveInterval = null;

        onWillStart(async () => {
            await this.loadExamData();
        });

        onMounted(() => {
            this.startTimers();
            this.enterFullscreen();
            this.loadFromLocalStorage();
            document.addEventListener("visibilitychange", this._onVisibility);
        });

        onWillUnmount(() => {
            this.stopTimers();
            document.removeEventListener("visibilitychange", this._onVisibility);
        });
    }

    get attemptId() {
        const el = document.getElementById("exam_session_app");
        return el ? parseInt(el.dataset.attemptId) : 0;
    }

    get examId() {
        const el = document.getElementById("exam_session_app");
        return el ? parseInt(el.dataset.examId) : 0;
    }

    getToken() {
        return (
            document.cookie
                .split(";")
                .find((c) => c.trim().startsWith("session_id="))
                ?.split("=")[1] || ""
        );
    }

    // ── Data Loading ──────────────────────────────────────────────────

    async loadExamData() {
        try {
            const response = await fetch(`/api/exam/${this.examId}/session`, {
                headers: { Authorization: `Bearer ${this.getToken()}` },
            });
            const data = await response.json();
            this.state.examData = data;
            this.state.timeRemaining =
                data.sections?.[0]?.time_limit_sec || 3600;
            this.state.totalTimeRemaining = data.total_time_sec || 7200;
            if (data.saved_answers) {
                for (const ans of data.saved_answers) {
                    this.state.answers[ans.question_id] = ans.answer;
                }
            }
            this.state.loading = false;
        } catch (e) {
            console.error("Failed to load exam data:", e);
        }
    }

    // ── Timers ────────────────────────────────────────────────────────

    startTimers() {
        this.timerInterval = setInterval(() => {
            if (this.state.timeRemaining > 0) {
                this.state.timeRemaining--;
                this.state.totalTimeRemaining--;
            } else {
                this.autoSubmitSection();
            }
        }, 1000);
        this.autosaveInterval = setInterval(
            () => this.autosave(),
            AUTOSAVE_INTERVAL
        );
    }

    stopTimers() {
        if (this.timerInterval) clearInterval(this.timerInterval);
        if (this.autosaveInterval) clearInterval(this.autosaveInterval);
    }

    enterFullscreen() {
        const el = document.documentElement;
        if (el.requestFullscreen) {
            el.requestFullscreen().catch(() => {});
        }
    }

    formatTime(seconds) {
        const m = Math.floor(seconds / 60);
        const s = seconds % 60;
        return `${m.toString().padStart(2, "0")}:${s.toString().padStart(2, "0")}`;
    }

    get timerClass() {
        if (this.state.timeRemaining < 60) return "ec-timer ec-timer--critical";
        if (this.state.timeRemaining < 300) return "ec-timer ec-timer--warning";
        return "ec-timer";
    }

    // ── Section / Question Navigation ─────────────────────────────────

    get currentSection() {
        return this.state.examData?.sections?.[this.state.currentSectionIdx];
    }

    get currentQuestion() {
        return this.currentSection?.questions?.[this.state.currentQuestionIdx];
    }

    get totalQuestions() {
        return this.currentSection?.questions?.length || 0;
    }

    get answeredCount() {
        const section = this.currentSection;
        if (!section) return 0;
        return section.questions.filter(
            (q) => this.state.answers[q.id] !== undefined
        ).length;
    }

    get sections() {
        return this.state.examData?.sections || [];
    }

    get questionDots() {
        const section = this.currentSection;
        if (!section) return [];
        return section.questions.map((q, idx) => ({
            idx,
            id: q.id,
            answered: this.state.answers[q.id] !== undefined,
            flagged: !!this.state.flagged[q.id],
            current: idx === this.state.currentQuestionIdx,
        }));
    }

    get hasPrev() {
        return this.state.currentQuestionIdx > 0;
    }

    get hasNext() {
        return this.state.currentQuestionIdx < this.totalQuestions - 1;
    }

    get isLastSection() {
        return (
            this.state.currentSectionIdx >=
            (this.state.examData?.sections?.length || 1) - 1
        );
    }

    nextQuestion() {
        if (this.state.currentQuestionIdx < this.totalQuestions - 1) {
            this.state.currentQuestionIdx++;
        }
    }

    prevQuestion() {
        if (this.state.currentQuestionIdx > 0) {
            this.state.currentQuestionIdx--;
        }
    }

    goToQuestion(idx) {
        this.state.currentQuestionIdx = idx;
        this.state.showReview = false;
    }

    switchSection(idx) {
        this.state.currentSectionIdx = idx;
        this.state.currentQuestionIdx = 0;
        const section = this.state.examData?.sections?.[idx];
        if (section?.time_limit_sec) {
            this.state.timeRemaining = section.time_limit_sec;
        }
    }

    nextSection() {
        const sections = this.state.examData?.sections || [];
        if (this.state.currentSectionIdx < sections.length - 1) {
            this.state.currentSectionIdx++;
            this.state.currentQuestionIdx = 0;
            this.state.timeRemaining =
                this.currentSection?.time_limit_sec || 3600;
        }
    }

    // ── Answer Management ─────────────────────────────────────────────

    setAnswer(questionId, value) {
        this.state.answers[questionId] = value;
        this.saveToLocalStorage();
    }

    onAnswer(ev) {
        if (ev.detail) {
            this.setAnswer(ev.detail.questionId, ev.detail.value);
        }
    }

    toggleFlag() {
        const q = this.currentQuestion;
        if (!q) return;
        this.state.flagged[q.id] = !this.state.flagged[q.id];
    }

    get isCurrentFlagged() {
        const q = this.currentQuestion;
        return q ? !!this.state.flagged[q.id] : false;
    }

    // ── LocalStorage Persistence ──────────────────────────────────────

    saveToLocalStorage() {
        try {
            localStorage.setItem(
                `exam_${this.attemptId}`,
                JSON.stringify({
                    answers: this.state.answers,
                    flagged: this.state.flagged,
                    currentSectionIdx: this.state.currentSectionIdx,
                    currentQuestionIdx: this.state.currentQuestionIdx,
                    timeRemaining: this.state.timeRemaining,
                })
            );
        } catch (e) {
            // storage full or unavailable
        }
    }

    loadFromLocalStorage() {
        try {
            const saved = localStorage.getItem(`exam_${this.attemptId}`);
            if (saved) {
                const data = JSON.parse(saved);
                Object.assign(this.state.answers, data.answers || {});
                Object.assign(this.state.flagged, data.flagged || {});
            }
        } catch (e) {
            // corrupt data
        }
    }

    // ── Server Autosave ───────────────────────────────────────────────

    async autosave() {
        try {
            const answers = Object.entries(this.state.answers).map(
                ([qid, ans]) => ({
                    question_id: parseInt(qid),
                    answer: ans,
                })
            );
            await fetch(`/api/exam/${this.examId}/autosave`, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    attempt_id: this.attemptId,
                    answers,
                    current_section: this.currentSection?.skill || "",
                    time_remaining_sec: this.state.timeRemaining,
                }),
            });
        } catch (e) {
            console.warn("Autosave failed:", e);
        }
    }

    // ── Visibility tracking (tab-switch guard) ────────────────────────

    _onVisibility = () => {
        if (document.visibilityState === "visible") {
            this.autosave();
        }
    };

    // ── Submit Flow ───────────────────────────────────────────────────

    autoSubmitSection() {
        const sections = this.state.examData?.sections || [];
        if (this.state.currentSectionIdx < sections.length - 1) {
            this.nextSection();
        } else {
            this.submitExam();
        }
    }

    showReviewPanel() {
        this.state.showReview = true;
    }

    hideReviewPanel() {
        this.state.showReview = false;
    }

    confirmSubmit() {
        this.state.showConfirmSubmit = true;
    }

    cancelSubmit() {
        this.state.showConfirmSubmit = false;
    }

    async submitExam() {
        this.stopTimers();
        this.state.submitted = true;
        this.state.showConfirmSubmit = false;
        this.state.submitMessage = "Submitting your answers...";
        try {
            const answers = Object.entries(this.state.answers).map(
                ([qid, ans]) => ({
                    question_id: parseInt(qid),
                    answer: ans,
                })
            );
            const response = await fetch(`/api/exam/${this.examId}/submit`, {
                method: "POST",
                headers: { "Content-Type": "application/json" },
                body: JSON.stringify({
                    attempt_id: this.attemptId,
                    answers,
                }),
            });
            await response.json();
            localStorage.removeItem(`exam_${this.attemptId}`);
            this.state.submitMessage =
                "Exam submitted successfully! Redirecting...";
            setTimeout(() => {
                window.location.href = `/my/exam/${this.attemptId}/results`;
            }, 2000);
        } catch (e) {
            console.error("Submit failed:", e);
            this.state.submitMessage =
                "Submission failed. Please try again.";
            this.state.submitted = false;
        }
    }

    // ── Review summary helpers ────────────────────────────────────────

    get reviewSections() {
        const sections = this.state.examData?.sections || [];
        return sections.map((section, sIdx) => ({
            ...section,
            sIdx,
            questions: section.questions.map((q, qIdx) => ({
                ...q,
                qIdx,
                sIdx,
                answered: this.state.answers[q.id] !== undefined,
                flagged: !!this.state.flagged[q.id],
            })),
        }));
    }

    get totalAnswered() {
        return Object.keys(this.state.answers).length;
    }

    get totalAllQuestions() {
        const sections = this.state.examData?.sections || [];
        return sections.reduce((sum, s) => sum + (s.questions?.length || 0), 0);
    }

    get totalFlagged() {
        return Object.values(this.state.flagged).filter(Boolean).length;
    }

    reviewGoTo(sIdx, qIdx) {
        this.state.currentSectionIdx = sIdx;
        this.state.currentQuestionIdx = qIdx;
        this.state.showReview = false;
    }
}

// ── Auto-mount on page load ───────────────────────────────────────────

function mountExamApp() {
    const target = document.getElementById("exam_session_app");
    if (target) {
        const { mount } = owl;
        mount(ExamApp, target);
    }
}

if (document.readyState === "loading") {
    document.addEventListener("DOMContentLoaded", mountExamApp);
} else {
    mountExamApp();
}
