import React, { cloneElement, useRef } from 'react';
import styled from 'styled-components';

import type { PropsWithChildren, ReactElement } from 'react';

import { useOutsideClick, useControlledState } from '@redocly/theme/core/hooks';
import { ChevronDownIcon } from '@redocly/theme/icons/ChevronDownIcon/ChevronDownIcon';
import { ChevronUpIcon } from '@redocly/theme/icons/ChevronUpIcon/ChevronUpIcon';

export type DropdownProps = PropsWithChildren<{
  trigger: React.ReactNode;
  triggerEvent?: 'click' | 'hover';
  placement?: 'top' | 'bottom';
  alignment?: 'start' | 'end';

  active?: boolean;
  closeOnClick?: boolean;

  dataAttributes?: Record<string, string>;
  className?: string;
  withArrow?: boolean;

  onClick?: (event: React.UIEvent) => void;
}>;

export function Dropdown({
  children,
  className,
  active,
  trigger,
  triggerEvent = 'click',
  closeOnClick = true,
  withArrow,
  dataAttributes,
  placement,
  alignment,
  onClick,
}: DropdownProps): JSX.Element {
  const dropdownRef = useRef<HTMLDivElement | null>(null);
  const [isOpen, setIsOpen] = useControlledState<boolean>(false, active);

  const handleOpen = () => {
    setIsOpen(true);
  };

  const handleClose = () => {
    setIsOpen(false);
  };

  const handleChildClick = () => {
    handleClose();
  };

  const handleToggle = (event: React.UIEvent) => {
    event.stopPropagation();
    event.preventDefault();
    setIsOpen(!isOpen);
  };

  const handleKeyDown = (event: React.KeyboardEvent) => {
    if (event.key === 'Enter' || event.key === ' ') {
      handleToggle(event);
    }
  };

  useOutsideClick(dropdownRef, handleClose);

  const triggerChild = React.Children.only(trigger) as ReactElement;

  const dropdownTrigger = cloneElement(triggerChild, {
    onClick: triggerEvent === 'click' ? handleToggle : undefined,
    icon: withArrow ? isOpen ? <ChevronUpIcon /> : <ChevronDownIcon /> : undefined,
    ...(withArrow ? { iconPosition: 'right' } : {}),
    ...triggerChild.props,
    onKeyDown: triggerEvent === 'click' ? handleKeyDown : undefined,
  });

  return (
    <DropdownWrapper
      data-component-name="Dropdown/Dropdown"
      data-testid="dropdown"
      {...dataAttributes}
      className={className}
      ref={dropdownRef}
      onPointerEnter={triggerEvent === 'hover' ? handleOpen : undefined}
      onPointerLeave={triggerEvent === 'hover' ? handleClose : undefined}
      onClick={onClick}
    >
      {dropdownTrigger}

      <ChildrenWrapper
        placement={placement}
        alignment={alignment}
        isOpen={isOpen}
        onClick={closeOnClick ? handleChildClick : undefined}
      >
        {children}
      </ChildrenWrapper>
    </DropdownWrapper>
  );
}

const DropdownWrapper = styled.div`
  --button-gap: var(--spacing-xxs);

  display: flex;
  gap: var(--spacing-xxs);
  align-items: center;
  justify-content: space-between;
  cursor: pointer;
  height: 100%;
  appearance: none;
  padding: 0;
  margin: 0;
  position: relative;

  text-decoration: none;
`;

const ChildrenWrapper = styled.div<{ placement?: string; alignment?: string; isOpen?: boolean }>`
  position: absolute;
  top: ${({ placement }) => (placement === 'top' ? 'auto' : '100%')};
  bottom: ${({ placement }) => (placement === 'top' ? '100%' : 'auto')};
  left: ${({ alignment }) => (alignment === 'start' ? '0' : 'auto')};
  right: ${({ alignment }) => (alignment === 'end' ? '0' : 'auto')};
  display: ${({ isOpen }) => (isOpen ? 'block' : 'none')};

  z-index: var(--z-index-raised);
`;
