import React, { createRef, useContext, useEffect, useMemo, useState } from 'react';
import { I18nextProvider } from 'react-i18next';
import { Provider } from 'react-redux';
import { createRenderChildNodes } from '../../createRenderChildNodes';
import { findChildElement, query } from '../../dom-utils';
import { changeLanguage, initI18n, useExamTranslation } from '../../i18n';
import { examTitleId } from '../../ids';
import { parseExamStructure } from '../../parser/parseExamStructure';
import { scrollToHash } from '../../scrollToHash';
import { initializeExamStore } from '../../store';
import { useCached } from '../../useCached';
import DocumentTitle from '../DocumentTitle';
import NotificationIcon from '../NotificationIcon';
import RenderChildNodes from '../RenderChildNodes';
import SectionElement from '../SectionElement';
import { AnnotationProvider } from '../context/AnnotationProvider';
import { CommonExamContext, withCommonExamContext } from '../context/CommonExamContext';
import { withExamContext } from '../context/ExamContext';
import { TOCContext } from '../context/TOCContext';
import mkAttachmentLink from '../shared/AttachmentLink';
import mkAttachmentLinks from '../shared/AttachmentLinks';
import Audio from '../shared/Audio';
import AudioGroup from '../shared/AudioGroup';
import AudioTest from '../shared/AudioTest';
import ExamTranslation from '../shared/ExamTranslation';
import File from '../shared/File';
import { Footer } from '../shared/Footer';
import Formula from '../shared/Formula';
import Image from '../shared/Image';
import ImageOverlay from '../shared/ImageOverlay';
import { QuestionNumber } from '../shared/QuestionNumber';
import References from '../shared/References';
import { mkTableOfContents } from '../shared/TableOfContents';
import { VersionNumber } from '../shared/VersionNumber';
import Video from '../shared/Video';
import ExamAttachment from './Attachment';
import ChoiceAnswer from './ChoiceAnswer';
import { DNDAnswerContainer } from './DNDAnswerContainer';
import DropdownAnswer from './DropdownAnswer';
import ExamFooter from './ExamFooter';
import ExamInstruction from './ExamInstruction';
import ExternalMaterial from './ExternalMaterial';
import GoToExamineAnswersButton from './GoToExamineAnswersButton';
import Hints from './Hints';
import Question from './Question';
import QuestionInstruction from './QuestionInstruction';
import QuestionTitle from './QuestionTitle';
import Section from './Section';
import SectionInstruction from './SectionInstruction';
import SectionTitle from './SectionTitle';
import { StudentNameHeader } from './StudentNameHeader';
import TextAnswer from './TextAnswer';
import { UndoView } from './UndoView';
import ErrorIndicator from './internal/ErrorIndicator';
import SaveIndicator from './internal/SaveIndicator';
import AudioAnswer from './AudioAnswer';
import { withAudioRecorderContext } from '../context/AudioRecorderContext';
export const renderChildNodesBase = createRenderChildNodes({
    attachment: ExamAttachment,
    'attachment-link': mkAttachmentLink('link'),
    'attachment-links': mkAttachmentLinks('link'),
    audio: Audio,
    'audio-title': RenderChildNodes,
    'audio-group': AudioGroup,
    'audio-test': AudioTest,
    'choice-answer': ChoiceAnswer,
    'dnd-answer-container': DNDAnswerContainer,
    'dropdown-answer': DropdownAnswer,
    'exam-footer': ExamFooter,
    'external-material': ExternalMaterial,
    file: File,
    formula: Formula,
    image: Image,
    question: Question,
    'question-number': QuestionNumber,
    translation: ExamTranslation,
    'question-instruction': QuestionInstruction,
    'question-title': QuestionTitle,
    hints: Hints,
    references: References,
    'scored-text-answer': TextAnswer,
    'scored-text-answers': Hints,
    'section-instruction': SectionInstruction,
    section: Section,
    'section-title': SectionTitle,
    'text-answer': TextAnswer,
    video: Video,
    'image-overlay': ImageOverlay,
    'audio-answer': AudioAnswer
});
const Exam = ({ doc, casStatus, answers, restrictedAudioPlaybackStats, examServerApi, studentName, showUndoView, undoViewProps, annotationsEnabled, renderComponentOverrides = {} }) => {
    const { date, dateTimeFormatter, dayCode, examCode, language, resolveAttachment, root, subjectLanguage } = useContext(CommonExamContext);
    const renderChildNodes = useMemo(() => renderChildNodesBase(renderComponentOverrides), [renderComponentOverrides]);
    const examTitle = findChildElement(root, 'exam-title');
    const examInstruction = findChildElement(root, 'exam-instruction');
    const tableOfContents = findChildElement(root, 'table-of-contents');
    const externalMaterial = findChildElement(root, 'external-material');
    const examStylesheet = root.getAttribute('exam-stylesheet');
    const examRef = createRef();
    const store = useCached(() => initializeExamStore(parseExamStructure(doc), casStatus, answers, restrictedAudioPlaybackStats, examServerApi));
    const TableOfContentsSidebar = useCached(() => mkTableOfContents({
        showAttachmentLinks: true,
        showAnsweringInstructions: true,
        isInSidebar: true
    }));
    const TableOfContents = useCached(() => mkTableOfContents({
        showAttachmentLinks: true,
        showAnsweringInstructions: true,
        isInSidebar: false
    }));
    const i18n = useCached(() => initI18n(language, examCode, dayCode));
    useEffect(changeLanguage(i18n, language));
    useEffect(scrollToHash, []);
    const [allRefs, setAllRefs] = useState([]);
    const addRef = (ref) => {
        if (!allRefs.includes(ref)) {
            setAllRefs(prevRefs => {
                const nextAllRefs = [...prevRefs, ref];
                return nextAllRefs;
            });
        }
    };
    useEffect(() => {
        const observer = new IntersectionObserver(callback);
        const observableElements = allRefs;
        observableElements.forEach(element => observer.observe(element));
        return () => {
            observableElements.forEach(element => observer.unobserve(element));
        };
    }, [allRefs]);
    const callback = (entries) => entries.forEach(entry => {
        const dataTOCId = entry.target.getAttribute('data-toc-id');
        setVisibleElements(prevEntries => entry.isIntersecting ? [...prevEntries, dataTOCId] : prevEntries.filter(entries => entries !== dataTOCId));
    });
    const [visibleElements, setVisibleElements] = useState([]);
    const isInViewport = (element) => {
        const offset = 100; // must be at least this far away from viewport edges
        const rect = element.getBoundingClientRect();
        return rect.top >= offset && rect.bottom <= window.innerHeight - offset;
    };
    useEffect(() => {
        visibleElements.forEach(element => {
            const displayNumber = element.replace('question-', '');
            const naviQuestionTitle = document.querySelector(`.table-of-contents li[data-list-number="${displayNumber}."]`);
            if (naviQuestionTitle) {
                const isVisible = isInViewport(naviQuestionTitle);
                const sideNavigation = document.querySelector(`.sidebar-toc-container .table-of-contents`);
                if (!isVisible && !!sideNavigation) {
                    const navHeight = sideNavigation.getBoundingClientRect().height;
                    const scrollToPos = naviQuestionTitle.offsetTop - navHeight / 2;
                    sideNavigation.scrollTo({ behavior: 'smooth', top: scrollToPos });
                }
            }
        });
    }, [visibleElements]);
    // TODO: Remove 'isNewKoeVersion' checks when old Koe version is not supported anymore
    // Here "old" means versions where student can not examine answers on a separate page after answering questions
    const isNewKoeVersion = examServerApi.examineExam !== undefined;
    const isPreview = studentName === '[Kokelaan Nimi]';
    return (React.createElement(Provider, { store: store },
        React.createElement(AnnotationProvider, { annotationsEnabled: annotationsEnabled },
            React.createElement(TOCContext.Provider, { value: {
                    visibleTOCElements: visibleElements,
                    addRef
                } },
                React.createElement(I18nextProvider, { i18n: i18n },
                    React.createElement("main", { className: "e-exam", lang: subjectLanguage, "aria-labelledby": examTitleId, ref: examRef },
                        React.createElement(React.StrictMode, null),
                        examStylesheet && React.createElement("link", { rel: "stylesheet", href: resolveAttachment(examStylesheet) }),
                        React.createElement("div", { className: "e-toc-and-exam" },
                            tableOfContents && (React.createElement("div", { className: "sidebar-toc-container", "aria-hidden": "true" },
                                React.createElement(TableOfContentsSidebar, { element: tableOfContents, renderChildNodes, renderComponentOverrides }))),
                            React.createElement("div", { className: "main-exam-container" },
                                React.createElement("div", { className: "main-exam" },
                                    React.createElement(StudentNameHeader, { studentName: studentName }),
                                    React.createElement(SectionElement, { "aria-labelledby": examTitleId },
                                        examTitle && React.createElement(DocumentTitle, { id: examTitleId }, renderChildNodes(examTitle)),
                                        date && (React.createElement("p", null,
                                            React.createElement("strong", null, dateTimeFormatter.format(date)))),
                                        React.createElement(NoAttachmentsNotification, { root: root }),
                                        examInstruction && (React.createElement(ExamInstruction, { element: examInstruction, renderChildNodes, renderComponentOverrides })),
                                        tableOfContents && (React.createElement("div", { className: "main-toc-container" },
                                            React.createElement(TableOfContents, { element: tableOfContents,
                                                renderChildNodes,
                                                renderComponentOverrides }))),
                                        externalMaterial && (React.createElement(ExternalMaterial, { element: externalMaterial,
                                            renderChildNodes,
                                            renderComponentOverrides,
                                            forceRender: true }))),
                                    renderChildNodes(root),
                                    (isPreview || isNewKoeVersion) && (React.createElement("div", { className: "e-examine-exam" },
                                        React.createElement(GoToExamineAnswersButton, null),
                                        React.createElement(ProceedToExamineAnswersText, null)))))),
                        (isPreview || isNewKoeVersion) && (React.createElement(Footer, null,
                            React.createElement("div", { className: "e-footer-version-number-container" },
                                React.createElement(VersionNumber, null)))),
                        React.createElement("div", { className: "e-indicators-container" },
                            React.createElement(ErrorIndicator, null),
                            React.createElement(SaveIndicator, null)),
                        showUndoView && isNewKoeVersion && React.createElement(UndoView, { ...undoViewProps, examServerApi: examServerApi })))))));
};
const NoAttachmentsNotification = ({ root }) => {
    const { t } = useExamTranslation();
    const hasAttachments = query(root, 'external-material');
    return hasAttachments ? null : (React.createElement("span", { className: "notification notification--inline" },
        React.createElement(NotificationIcon, null),
        t('no-attachments')));
};
const ProceedToExamineAnswersText = () => {
    const { t } = useExamTranslation();
    return (React.createElement("div", { className: "e-examine-exam-instructions", id: "examineExamInstructions" }, t('examine-exam.instructions')));
};
export default React.memo(withExamContext(withCommonExamContext(withAudioRecorderContext(Exam))));
//# sourceMappingURL=Exam.js.map