/** @jsxImportSource @emotion/react */
import React, { FunctionComponent } from 'react';
import { css } from 'twin.macro';

import useResizeObserver from '../hooks/useResizeObserver';
import CollapseExpandIcon from '../icons/CollapseExpandIcon';
import { AccordionContext } from './AccordionGroup';
import { TRANSITION_DURATION, TRANSITION_FUNCTION } from './constants';
import { AccordionBtn, AccordionBtnSummary, AccordionContent } from './styles';
import { AccordionProps, TransitionState } from './types';

export const Accordion: FunctionComponent<AccordionProps> = ({
  summary,
  children,
  ...props
}) => {
  const accordionId = React.useMemo(
    () =>
      `accordion-${Math.random()
        .toString(16)
        .slice(2)}`,
    [],
  );

  const [height, setHeight] = React.useState('0px');
  const resizeRef = useResizeObserver(
    React.useCallback(
      (entries) => {
        for (const entry of entries) {
          const { height } = entry.contentRect;
          setHeight(`${height}px`);
        }
      },
      [setHeight],
    ),
  );
  const [isOpen, setIsOpen] = React.useState(false);
  const [transitionState, setTransitionState] = React.useState<TransitionState>(
    isOpen ? 'opened' : 'closed',
  );
  React.useEffect(() => {
    let timeout = setTimeout(() => {
      setTransitionState((transitionState) => {
        if (transitionState === 'opening') {
          return 'opened';
        }
        if (transitionState === 'closing') {
          return 'closed';
        }
      });
      timeout = null;
    }, TRANSITION_DURATION);
    return () => {
      if (!timeout) return;
      clearTimeout(timeout);
    };
  }, [isOpen, setTransitionState]);

  React.useEffect(() => {
    if (isOpen) {
      if (transitionState !== 'opened') setTransitionState('opening');
    } else {
      if (transitionState !== 'closed') setTransitionState('closing');
    }
  }, [isOpen, setTransitionState]);

  const handleToggle = React.useCallback(
    (e: React.MouseEvent<HTMLButtonElement>) => {
      e.target.dispatchEvent(
        new CustomEvent('accordion', { bubbles: true, detail: accordionId }),
      );
      setIsOpen((state) => !state);
    },
    [setIsOpen],
  );

  const activeAccordion = React.useContext(AccordionContext);
  React.useEffect(() => {
    if (!activeAccordion || !accordionId) return;
    if (activeAccordion === accordionId) return;
    setIsOpen(false);
  }, [activeAccordion, accordionId, setIsOpen]);

  return (
    <div tw="border-solid border-b border-brand">
      <AccordionBtn id={accordionId} onClick={handleToggle}>
        <AccordionBtnSummary tw="">{summary}</AccordionBtnSummary>

        <CollapseExpandIcon
          duration={TRANSITION_DURATION}
          timingFunction={TRANSITION_FUNCTION}
          mode={isOpen ? 'collapse' : 'expand'}
        />
      </AccordionBtn>

      <AccordionContent
        aria-hidden={!isOpen}
        tabIndex={-1}
        isOpen={isOpen}
        transitionState={transitionState}
        css={css`
          height: ${isOpen ? height : 0};
        `}
        {...props}
      >
        <div ref={resizeRef}>{children}</div>
      </AccordionContent>
    </div>
  );
};

export default Accordion;
