/** @odoo-module */

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

// ═══════════════════════════════════════════════════════════════════════
// ExamMCQ — Single-choice radio buttons
// ═══════════════════════════════════════════════════════════════════════

export class ExamMCQ extends Component {
    static template = "encoach_exam_session.ExamMCQ";
    static props = {
        question: Object,
        answer: { type: [String, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    selectOption(optionKey) {
        this.props.onAnswer(this.props.question.id, optionKey);
    }

    get options() {
        const opts = this.props.question.options;
        if (Array.isArray(opts)) {
            return opts.map((o, i) => ({
                key: o.key || String.fromCharCode(65 + i),
                label: o.label || o.text || o,
            }));
        }
        if (opts && typeof opts === "object") {
            return Object.entries(opts).map(([key, label]) => ({ key, label }));
        }
        return [];
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamMCQMulti — Multi-choice checkboxes
// ═══════════════════════════════════════════════════════════════════════

export class ExamMCQMulti extends Component {
    static template = "encoach_exam_session.ExamMCQMulti";
    static props = {
        question: Object,
        answer: { type: [Array, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    toggleOption(optionKey) {
        const current = Array.isArray(this.props.answer)
            ? [...this.props.answer]
            : [];
        const idx = current.indexOf(optionKey);
        if (idx >= 0) {
            current.splice(idx, 1);
        } else {
            current.push(optionKey);
        }
        this.props.onAnswer(this.props.question.id, current);
    }

    isChecked(optionKey) {
        return Array.isArray(this.props.answer) && this.props.answer.includes(optionKey);
    }

    get options() {
        const opts = this.props.question.options;
        if (Array.isArray(opts)) {
            return opts.map((o, i) => ({
                key: o.key || String.fromCharCode(65 + i),
                label: o.label || o.text || o,
            }));
        }
        if (opts && typeof opts === "object") {
            return Object.entries(opts).map(([key, label]) => ({ key, label }));
        }
        return [];
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamGapFill — Inline text inputs within a passage
// ═══════════════════════════════════════════════════════════════════════

export class ExamGapFill extends Component {
    static template = "encoach_exam_session.ExamGapFill";
    static props = {
        question: Object,
        answer: { type: [Object, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    onGapInput(gapIdx, ev) {
        const current = this.props.answer ? { ...this.props.answer } : {};
        current[gapIdx] = ev.target.value;
        this.props.onAnswer(this.props.question.id, current);
    }

    get gaps() {
        return this.props.question.gaps || [];
    }

    gapValue(gapIdx) {
        return this.props.answer?.[gapIdx] || "";
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamTFNG — True / False / Not Given selector
// ═══════════════════════════════════════════════════════════════════════

export class ExamTFNG extends Component {
    static template = "encoach_exam_session.ExamTFNG";
    static props = {
        question: Object,
        answer: { type: [String, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    select(value) {
        this.props.onAnswer(this.props.question.id, value);
    }

    get choices() {
        return [
            { key: "true", label: "True" },
            { key: "false", label: "False" },
            { key: "not_given", label: "Not Given" },
        ];
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamAudioRecorder — Record audio (speaking tasks)
// ═══════════════════════════════════════════════════════════════════════

export class ExamAudioRecorder extends Component {
    static template = "encoach_exam_session.ExamAudioRecorder";
    static props = {
        question: Object,
        answer: { type: [String, Object, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    setup() {
        this.state = useState({
            recording: false,
            recordedUrl: null,
            duration: 0,
            error: null,
        });
        this.mediaRecorder = null;
        this.chunks = [];
        this.durationInterval = null;
    }

    async startRecording() {
        try {
            const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
            this.mediaRecorder = new MediaRecorder(stream, {
                mimeType: "audio/webm;codecs=opus",
            });
            this.chunks = [];
            this.mediaRecorder.ondataavailable = (e) => {
                if (e.data.size > 0) this.chunks.push(e.data);
            };
            this.mediaRecorder.onstop = () => {
                const blob = new Blob(this.chunks, { type: "audio/webm" });
                this.state.recordedUrl = URL.createObjectURL(blob);
                this.props.onAnswer(this.props.question.id, {
                    type: "audio",
                    blob_url: this.state.recordedUrl,
                    duration: this.state.duration,
                });
                stream.getTracks().forEach((t) => t.stop());
            };
            this.mediaRecorder.start();
            this.state.recording = true;
            this.state.duration = 0;
            this.durationInterval = setInterval(() => {
                this.state.duration++;
            }, 1000);
        } catch (e) {
            this.state.error = "Microphone access denied. Please allow microphone access.";
        }
    }

    stopRecording() {
        if (this.mediaRecorder && this.state.recording) {
            this.mediaRecorder.stop();
            this.state.recording = false;
            if (this.durationInterval) clearInterval(this.durationInterval);
        }
    }

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

// ═══════════════════════════════════════════════════════════════════════
// ExamRichEditor — Writing task with rich text
// ═══════════════════════════════════════════════════════════════════════

export class ExamRichEditor extends Component {
    static template = "encoach_exam_session.ExamRichEditor";
    static props = {
        question: Object,
        answer: { type: [String, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    setup() {
        this.editorRef = useRef("editor");
        this.state = useState({
            wordCount: this._countWords(this.props.answer || ""),
        });
    }

    onInput(ev) {
        const text = ev.target.value || "";
        this.state.wordCount = this._countWords(text);
        this.props.onAnswer(this.props.question.id, text);
    }

    _countWords(text) {
        return text
            .trim()
            .split(/\s+/)
            .filter((w) => w.length > 0).length;
    }

    get minWords() {
        return this.props.question.min_words || 150;
    }

    get maxWords() {
        return this.props.question.max_words || 300;
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamReadingPassage — Scrollable passage display
// ═══════════════════════════════════════════════════════════════════════

export class ExamReadingPassage extends Component {
    static template = "encoach_exam_session.ExamReadingPassage";
    static props = {
        passage: { type: [Object, String, { value: undefined }], optional: true },
    };

    get passageTitle() {
        if (typeof this.props.passage === "object") {
            return this.props.passage?.title || "Reading Passage";
        }
        return "Reading Passage";
    }

    get passageContent() {
        if (typeof this.props.passage === "object") {
            return this.props.passage?.content || "";
        }
        return this.props.passage || "";
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamNumericalInput — Number input with optional tolerance
// ═══════════════════════════════════════════════════════════════════════

export class ExamNumericalInput extends Component {
    static template = "encoach_exam_session.ExamNumericalInput";
    static props = {
        question: Object,
        answer: { type: [Number, String, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    onInput(ev) {
        const val = ev.target.value;
        this.props.onAnswer(this.props.question.id, val);
    }

    get tolerance() {
        return this.props.question.tolerance;
    }

    get unit() {
        return this.props.question.unit || "";
    }
}

// ═══════════════════════════════════════════════════════════════════════
// ExamCodeEditor — Code editing textarea
// ═══════════════════════════════════════════════════════════════════════

export class ExamCodeEditor extends Component {
    static template = "encoach_exam_session.ExamCodeEditor";
    static props = {
        question: Object,
        answer: { type: [String, { value: undefined }], optional: true },
        onAnswer: Function,
    };

    setup() {
        this.editorRef = useRef("codeEditor");

        onMounted(() => {
            if (this.editorRef.el) {
                this.editorRef.el.addEventListener("keydown", this._onKeydown);
            }
        });

        onWillUnmount(() => {
            if (this.editorRef.el) {
                this.editorRef.el.removeEventListener("keydown", this._onKeydown);
            }
        });
    }

    _onKeydown = (ev) => {
        if (ev.key === "Tab") {
            ev.preventDefault();
            const ta = ev.target;
            const start = ta.selectionStart;
            const end = ta.selectionEnd;
            ta.value = ta.value.substring(0, start) + "    " + ta.value.substring(end);
            ta.selectionStart = ta.selectionEnd = start + 4;
            this.props.onAnswer(this.props.question.id, ta.value);
        }
    };

    onInput(ev) {
        this.props.onAnswer(this.props.question.id, ev.target.value);
    }

    get language() {
        return this.props.question.language || "python";
    }

    get starterCode() {
        return this.props.question.starter_code || "";
    }
}
