import React, { useRef, useState, useEffect } from 'react';
import PropTypes from 'prop-types';

import Icon from '../../../icon/Icon';
import Button from '../../../button/Button';
import { createNamespace } from '../../../../tools/namingTools';
import { useReportRect } from '../../../../tools/dimensions/reportRect';
// IMPORTANT: (s)css should be imported after other atoms/components
import './styles/ModalContents.scss';

const n = createNamespace('ModalContents');

const minimumEdgeDistance = 10; // px

const ModalContents = ({
    children,
    onClose,
    animTime,
    left: originalLeft,
    top: originalTop
}) => {
    const contentRef = useRef(null);
    const [isCentered, setIsCentered] = useState(false);
    const [translatedTop, setTranslatedTop] = useState(0);
    const [translatedLeft, setTranslatedLeft] = useState(0);
    const [lastActiveElement, setLastActiveElement] = useState(null);

    useReportRect(contentRef, rect => {
        const availableWidth = window.innerWidth;
        const availableHeight = window.innerHeight;
        const { left, width, height, right, bottom } = rect;
        const realBottom = bottom - translatedTop;
        const realLeft = left - translatedLeft;
        const realRight = right - translatedLeft;
        // window can fit only one element, center it
        if (availableWidth < width * 2) {
            setIsCentered(true);
        } else if (realLeft < 0) {
            setTranslatedLeft(-realLeft + minimumEdgeDistance);
        } else if (realRight > availableWidth) {
            setTranslatedLeft((availableWidth - realRight) - minimumEdgeDistance);
        }
        if (realBottom > availableHeight && height < availableHeight) {
            setTranslatedTop(availableHeight - realBottom - minimumEdgeDistance);
        }
    });

    const wrapperProps = n('content', isCentered && 'centered').withVariables({
        animTime: `${animTime}ms`,
        left: `${originalLeft}px`,
        top: `${originalTop}px`,
        translatedTop: `${translatedTop}px`,
        translatedLeft: `${translatedLeft}px`
    }).props;

    function trapFocus(modal) {
        const focusableElements = modal.querySelectorAll(
            'a, button, input, textarea, select, [tabindex]:not([tabindex="-1"])'
        );
        const firstElement = focusableElements[0];
        const lastElement = focusableElements[focusableElements.length - 1];

        // Focus the first element if it exists
        if (firstElement) {
            firstElement.focus();
        }

        modal.addEventListener('keydown', e => {
            if (e.key === 'Tab') {
                if (e.shiftKey) {
                    // Shift + Tab (Backward)
                    if (document.activeElement === firstElement) {
                        e.preventDefault();
                        lastElement.focus();
                    }
                } else if (document.activeElement === lastElement) {
                    e.preventDefault();
                    firstElement.focus();
                }
            }
        });
    }

    useEffect(() => {
        // Store the currently active element before opening the modal (to refocus it later)
        setLastActiveElement(document.activeElement);
        trapFocus(contentRef.current);
    }, []);

    const closeModal = (...args) => {
        lastActiveElement?.focus();
        onClose(...args);
    };

    const closeOnEscape = e => {
        if (e.key === 'Escape') {
            closeModal();
        }
    };

    return (
        <div // eslint-disable-line jsx-a11y/no-noninteractive-element-interactions
            {...wrapperProps}
            ref={contentRef}
            tabIndex={-1}
            role="dialog"
            aria-modal="true"
            onKeyDown={closeOnEscape}
        >
            <div {...n('closeButton').props}>
                <Button buttonType="icon" onClick={closeModal}>
                    <span {...n('closeButtonText').props}>X</span>
                    <Icon {...n('closeButtonIcon').props} type="close" />
                </Button>
            </div>
            <div>
                {children}
            </div>
        </div>
    );
};

ModalContents.propTypes = {
    onClose: PropTypes.func,
    animTime: PropTypes.number,
    left: PropTypes.number,
    top: PropTypes.number
};

ModalContents.defaultProps = {
    onClose: () => null,
    animTime: 0,
    left: 0,
    top: 0
};

export default ModalContents;
