import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
import { useEffect, useRef, useState, forwardRef, useCallback } from 'react';
import { createPortal } from 'react-dom';
import { cap, getActiveElement, getFocusables, withTestIds } from '../../utils';
import Flex from '../Flex';
import MetaList from '../MetaList';
import Icon from '../Icon';
import Image from '../Image';
import Text from '../Text';
import { useConfiguration, useConsolidatedRef, useDirection, useEvent, useFocusTrap, useI18n, useScrollToggle, useTestIds } from '../../hooks';
import ErrorState from '../ErrorState';
import Progress from '../Progress';
import FileVisual from '../File/FileVisual';
import Button from '../Button';
import Link from '../Link/Link';
import mimeTypes from '../File/mimeTypes.json';
import { getKindFromMimeType } from '../File/utils';
import { StyledHeader, StyledCountTracker, StyledInfo, StyledPreviewRegion, StyledNavButton, StyledMediaContainer, StyledLiveRegion, StyledLightbox, StyledContainer, StyledObject } from './Lightbox.styles';
import { getLightboxTestIds } from './Lightbox.test-ids';
const Lightbox = forwardRef(function Lightbox({ testId, items, defaultIndex = 0, cycle = false, onItemLoad, onItemError, onNavigate, onItemDownload, onAfterClose, ...restProps }, refArg) {
    const t = useI18n();
    const { start, end } = useDirection();
    const { portalTarget } = useConfiguration();
    const [currentIndex, setCurrentIndex] = useState(defaultIndex);
    const currentItem = items[currentIndex];
    const { disableScroll, enableScroll } = useScrollToggle();
    const lightboxRef = useConsolidatedRef(refArg);
    const headerRef = useRef(null);
    const closeButtonRef = useRef(null);
    const prevButtonRef = useRef(null);
    const nextButtonRef = useRef(null);
    const [open, setOpen] = useState(true);
    const mediaRef = useConsolidatedRef(currentItem.ref);
    const [liveText, setLiveText] = useState('');
    const countTrackerText = items.length > 1 ? t('x_of_y', [currentIndex + 1, items.length]) : '';
    const testIds = useTestIds(testId, getLightboxTestIds);
    const initiatorRef = useRef(null);
    const close = () => {
        setOpen(false);
        if (initiatorRef.current?.isConnected &&
            (initiatorRef.current instanceof HTMLElement || initiatorRef.current instanceof SVGElement))
            initiatorRef.current.focus();
    };
    const navigate = (direction) => {
        if (direction === 1) {
            if (currentIndex < items.length - 1) {
                setCurrentIndex(cur => cur + 1);
            }
            else if (cycle) {
                setCurrentIndex(0);
            }
        }
        else if (currentIndex > 0) {
            setCurrentIndex(cur => cur - 1);
        }
        else if (cycle) {
            setCurrentIndex(items.length - 1);
        }
    };
    const keyDownHandler = (e) => {
        if (e.repeat)
            return;
        if (e.key === 'Escape') {
            close();
        }
        else if (e.key === `Arrow${cap(end)}`) {
            navigate(1);
        }
        else if (e.key === `Arrow${cap(start)}`) {
            navigate(-1);
        }
    };
    useEvent('keydown', keyDownHandler);
    useFocusTrap(lightboxRef);
    useEffect(() => {
        setLiveText(`${currentItem.name}. ${countTrackerText ? `${countTrackerText}.` : ''}`);
    }, [currentItem.name, countTrackerText]);
    useEffect(() => {
        onNavigate?.(currentItem.id, currentIndex);
    }, [currentIndex]);
    useEffect(() => {
        const activeElement = getActiveElement();
        initiatorRef.current = activeElement;
        if (getFocusables(lightboxRef).length > 0)
            getFocusables(lightboxRef)[0].focus();
    }, []);
    const handleLoad = useCallback((e) => {
        onItemLoad?.(currentItem.id, e);
    }, [onItemLoad, currentItem.id]);
    const handleError = useCallback((e) => {
        onItemError?.(currentItem.id, e);
    }, [onItemError, currentItem.id]);
    // Object elements appear to need native event handlers bound as JSX does not work.
    // TODO: Follow up on reason why.
    useEffect(() => {
        if (!mediaRef.current || currentItem.format !== 'pdf')
            return;
        const pdfObject = mediaRef.current;
        pdfObject.addEventListener('load', handleLoad);
        pdfObject.addEventListener('error', handleError);
        return () => {
            pdfObject.removeEventListener('load', handleLoad);
            pdfObject.removeEventListener('error', handleError);
        };
    }, [currentItem]);
    let media;
    let validContent = true;
    let attachmentType = 'generic';
    if (currentItem.format === undefined) {
        validContent = !currentItem.error;
    }
    else {
        const extractMimeType = mimeTypes[currentItem.format.toLowerCase()];
        const getType = currentItem.format === 'url' ? 'link' : 'generic';
        attachmentType = extractMimeType ? getKindFromMimeType(extractMimeType) : getType;
        const previewableAttachmentTypes = ['pdf', 'image', 'link', 'video', 'audio'];
        validContent = previewableAttachmentTypes.includes(attachmentType)
            ? !!currentItem.src
            : !!attachmentType;
    }
    if (validContent) {
        const nonPreviewableContent = (_jsxs(_Fragment, { children: [_jsx(Text, { children: t('non_previewable', [
                        currentItem.format ? currentItem.format.toUpperCase() : currentItem.name
                    ]) }), onItemDownload && (_jsx(Button, { "aria-label": t('download'), onClick: () => onItemDownload(currentItem.id), "data-testid": testIds.nonPreviewableDownload, children: t('download') }))] }));
        const defaultContent = (_jsxs(Flex, { container: { direction: 'column', gap: 2, alignItems: 'center' }, as: StyledInfo, "data-testid": testIds.content, children: [_jsx(FileVisual, { type: attachmentType, size: 'l' }), attachmentType === 'link' && currentItem.src ? (_jsx(Link, { href: currentItem.src, "data-testid": testIds.link, children: currentItem.name })) : (nonPreviewableContent)] }));
        switch (attachmentType) {
            case 'image':
                media = currentItem.src && (_jsx(Image, { "data-testid": testIds.content, src: currentItem.src, alt: currentItem.description ?? t('description_unavailable'), onLoad: handleLoad, onError: handleError, ref: mediaRef }));
                break;
            case 'pdf':
                media = currentItem.src && (_jsx(_Fragment, { children: navigator.pdfViewerEnabled ? (_jsx(StyledObject, { "data-testid": testIds.content, data: currentItem.src, type: 'application/pdf', ref: mediaRef, children: currentItem.description ?? t('description_unavailable') })) : ({ defaultContent }) }));
                break;
            case 'video':
                media = currentItem.src && (
                // eslint-disable-next-line jsx-a11y/media-has-caption
                _jsx("video", { "data-testid": testIds.content, src: currentItem.src, controls: true, onLoadedData: handleLoad, onError: handleError, ref: mediaRef }));
                break;
            case 'audio':
                media = currentItem.src && (
                // eslint-disable-next-line jsx-a11y/media-has-caption
                _jsx("audio", { "data-testid": testIds.content, src: currentItem.src, controls: true, onLoadedData: handleLoad, onError: handleError, ref: mediaRef }));
                break;
            default: {
                media = defaultContent;
            }
        }
    }
    else {
        media = _jsx(Progress, { placement: 'block', delay: true });
    }
    const content = (_jsxs(StyledLightbox, { "data-testid": testIds.root, ...restProps, tabIndex: -1, ref: lightboxRef, open: open, role: 'dialog', "aria-modal": 'true', container: { alignItems: 'start', justify: 'start', direction: 'column' }, alpha: 0.9, variant: 'dark', transitionSpeed: 'slow', onBeforeTransitionIn: disableScroll, onAfterTransitionOut: () => {
            enableScroll();
            onAfterClose?.();
        }, children: [_jsxs(Flex, { as: StyledHeader, ref: headerRef, container: {
                    justify: 'between',
                    alignItems: 'center',
                    gap: 2
                }, onMouseDown: (e) => {
                    if (e.button !== 0)
                        return;
                    if (e.target === e.currentTarget)
                        close();
                }, children: [_jsx(StyledCountTracker, { "data-testid": testIds.pagination, "aria-hidden": 'true', children: countTrackerText }), _jsxs(Flex, { as: StyledInfo, container: {
                            wrap: 'wrap',
                            alignItems: 'center',
                            justify: 'center',
                            colGap: 2,
                            rowGap: 0.5
                        }, children: [_jsx(Text, { "data-testid": testIds.name, variant: 'primary', as: 'h2', children: currentItem.name }), currentItem.metadata && (_jsx(MetaList, { "data-testid": testIds.metadata, items: currentItem.metadata }))] }), _jsxs(Flex, { container: true, as: StyledContainer, children: [attachmentType !== 'link' && onItemDownload && (_jsx(Button, { "data-testid": testIds.download, variant: 'simple', "aria-label": t('download'), icon: true, onClick: () => onItemDownload(currentItem.id), children: _jsx(Icon, { name: 'download' }) })), _jsx(Button, { "data-testid": testIds.close, variant: 'simple', ref: closeButtonRef, "aria-label": t('close'), icon: true, onClick: close, children: _jsx(Icon, { name: 'times' }) })] })] }), _jsxs(Flex, { container: { justify: 'between' }, as: StyledPreviewRegion, item: { grow: 1, shrink: 0 }, children: [items.length > 1 && (_jsx(StyledNavButton, { "data-testid": testIds.prev, ref: prevButtonRef, variant: 'simple', "aria-label": t('pagination_prev'), hidden: !cycle && currentIndex === 0, icon: true, onClick: () => {
                            navigate(-1);
                        }, children: _jsx("span", { children: _jsx(Icon, { name: 'caret-left' }) }) })), _jsx(Flex, { item: { grow: 1 }, as: StyledMediaContainer, children: _jsx(Flex, { container: { alignItems: 'center', justify: 'center' }, onMouseDown: (e) => {
                                if (e.button !== 0)
                                    return;
                                if (e.target === e.currentTarget)
                                    close();
                            }, children: currentItem.error ? _jsx(ErrorState, { message: t('content_load_error') }) : media }) }), items.length > 1 && (_jsx(StyledNavButton, { "data-testid": testIds.next, ref: nextButtonRef, variant: 'simple', "aria-label": t('pagination_next'), hidden: !cycle && currentIndex === items.length - 1, icon: true, onClick: () => {
                            navigate(1);
                        }, children: _jsx("span", { children: _jsx(Icon, { name: 'caret-right' }) }) }))] }), _jsx(StyledLiveRegion, { "aria-live": 'polite', "aria-label": liveText })] }));
    return portalTarget ? createPortal(content, portalTarget) : content;
});
export default withTestIds(Lightbox, getLightboxTestIds);
//# sourceMappingURL=Lightbox.js.map