import type {ForwardedRef} from 'react';
import {forwardRef, useEffect} from 'react';
import isPropValid from '@emotion/is-prop-valid';
import {css} from '@emotion/react';
import styled from '@emotion/styled';
import {AnimatePresence, motion} from 'framer-motion';

import {space} from 'sentry/styles/space';

const PANEL_WIDTH = '50vw';
const PANEL_HEIGHT = '50vh';

const OPEN_STYLES = {
  bottom: {opacity: 1, x: 0, y: 0},
  right: {opacity: 1, x: 0, y: 0},
};

const COLLAPSED_STYLES = {
  bottom: {opacity: 0, x: 0, y: PANEL_HEIGHT},
  right: {opacity: 0, x: PANEL_WIDTH, y: 0},
};

type SlideOverPanelProps = {
  children: React.ReactNode;
  collapsed: boolean;
  onOpen?: () => void;
  slidePosition?: 'right' | 'bottom';
};

export default forwardRef(SlideOverPanel);

function SlideOverPanel(
  {collapsed, children, onOpen, slidePosition}: SlideOverPanelProps,
  ref: ForwardedRef<HTMLDivElement>
) {
  useEffect(() => {
    if (!collapsed && onOpen) {
      onOpen();
    }
  }, [collapsed, onOpen]);

  const openStyle = slidePosition ? OPEN_STYLES[slidePosition] : OPEN_STYLES.right;

  const collapsedStyle = slidePosition
    ? COLLAPSED_STYLES[slidePosition]
    : COLLAPSED_STYLES.right;

  return (
    <AnimatePresence>
      {!collapsed && (
        <_SlideOverPanel
          ref={ref}
          initial={collapsedStyle}
          animate={openStyle}
          exit={collapsedStyle}
          slidePosition={slidePosition}
          transition={{
            type: 'spring',
            stiffness: 500,
            damping: 50,
          }}
        >
          {children}
        </_SlideOverPanel>
      )}
    </AnimatePresence>
  );
}

const _SlideOverPanel = styled(motion.div, {
  shouldForwardProp: prop =>
    ['initial', 'animate', 'exit', 'transition'].includes(prop) ||
    (prop !== 'collapsed' && isPropValid(prop)),
})<{
  slidePosition?: 'right' | 'bottom';
}>`
  position: fixed;

  top: ${space(2)};
  right: 0;
  bottom: ${space(2)};
  left: ${space(2)};

  overflow: auto;

  z-index: ${p => p.theme.zIndex.modal + 1};

  box-shadow: ${p => p.theme.dropShadowHeavy};
  background: ${p => p.theme.background};
  color: ${p => p.theme.textColor};

  text-align: left;

  @media (min-width: ${p => p.theme.breakpoints.small}) {
    ${p =>
      p.slidePosition === 'bottom'
        ? css`
            position: sticky;

            width: 100%;
            height: ${PANEL_HEIGHT};

            right: 0;
            bottom: 0;
            left: 0;
          `
        : css`
            position: fixed;

            width: ${PANEL_WIDTH};
            height: 100%;

            top: 0;
            right: 0;
            bottom: 0;
            left: auto;
          `}
  }
`;
