import React from 'react';
import styled from 'styled-components';

import type { JSX } from 'react';
import type { CodeBlockItems } from '@redocly/theme/components/CodeBlock/CodeBlock';

import { CodeBlockTabs } from '@redocly/theme/components/CodeBlock/CodeBlockTabs';
import { CopyButton } from '@redocly/theme/components/Buttons/CopyButton';
import { Tooltip } from '@redocly/theme/components/Tooltip/Tooltip';
import { useThemeHooks, useThemeConfig } from '@redocly/theme/core/hooks';
import { DeselectIcon } from '@redocly/theme/icons/DeselectIcon/DeselectIcon';
import { MaximizeIcon } from '@redocly/theme/icons/MaximizeIcon/MaximizeIcon';
import { MinimizeIcon } from '@redocly/theme/icons/MinimizeIcon/MinimizeIcon';
import { SelectIcon } from '@redocly/theme/icons/SelectIcon/SelectIcon';
import { WarningSquareIcon } from '@redocly/theme/icons/WarningSquareIcon/WarningSquareIcon';
import { Button } from '@redocly/theme/components/Button/Button';
import { CodeBlockDropdown } from '@redocly/theme/components/CodeBlock/CodeBlockDropdown';

export type CodeBlockControlsProps = {
  children?: React.ReactNode;
  className?: string;
  title?: React.ReactNode | string;
  controls?: ControlItems | false;
  tabs?: CodeBlockItems;
  dropdown?: CodeBlockItems;
};

type ControlItems = {
  copy?: CopyControlProps;
  expand?: ControlProps;
  collapse?: ControlProps;
  report?: ControlProps;
  select?: ControlProps;
  deselect?: ControlProps;
};

type ControlProps = {
  hidden?: boolean;
  label?: string;
  tooltipText?: string;
  onClick?: () => void;
  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
  props?: Record<string, any>;
};

type CopyControlProps = ControlProps & {
  data?: string;
  dataSource?: string;
  dataHash?: string;
  toasterPlacement?: 'left' | 'right' | 'top' | 'bottom';
  toasterText?: string;
  toasterDuration?: number;
  handleOutside?: boolean;
};

export type ControlItemType = 'text' | 'icon';

export function CodeBlockControls({
  children,
  className,
  title,
  controls,
  tabs,
  dropdown,
}: CodeBlockControlsProps): JSX.Element | null {
  const { codeSnippet } = useThemeConfig();
  const { useTelemetry, useTranslate } = useThemeHooks();
  const { translate } = useTranslate();
  const telemetry = useTelemetry();
  const controlsType = (codeSnippet?.elementFormat as ControlItemType) || 'icon';
  const { copy, expand, collapse, select, deselect, report } = controls || {
    copy: null,
    expand: null,
    collapse: null,
    select: null,
    deselect: null,
    report: null,
  };

  const isEmptyTitle = !title && !tabs && !dropdown;

  const defaultControls = controls ? (
    <>
      {title && <Title>{title}</Title>}
      {tabs && <CodeBlockTabs tabs={tabs} />}
      <ControlsWrapper>
        {dropdown && <CodeBlockDropdown {...dropdown} />}
        {report && !report.hidden && !report?.props?.hide ? (
          <Tooltip
            tip={translate('codeSnippet.report.tooltipText', 'Report a problem')}
            placement="top"
            arrowPosition="right"
          >
            <ControlButton
              variant="text"
              size="small"
              data-testid="report-button"
              icon={controlsType === 'icon' ? <WarningSquareIcon size="18px" /> : undefined}
              aria-label="Report a problem"
              {...report.props}
            >
              {controlsType != 'icon' && (report.props?.buttonText || 'Report')}
            </ControlButton>
          </Tooltip>
        ) : null}

        {expand && !codeSnippet?.expand?.hide ? (
          <Tooltip
            tip={translate('codeSnippet.expand.tooltipText', 'Expand all')}
            placement="top"
            arrowPosition="right"
          >
            <ControlButton
              variant="text"
              size="small"
              data-testid="expand-all"
              icon={controlsType === 'icon' ? <MaximizeIcon /> : undefined}
              aria-label="Expand all"
              onClick={expand?.onClick}
            >
              {controlsType !== 'icon' && (expand?.label || 'Expand all')}
            </ControlButton>
          </Tooltip>
        ) : null}

        {collapse && !codeSnippet?.collapse?.hide ? (
          <Tooltip
            tip={translate('codeSnippet.collapse.tooltipText', 'Collapse all')}
            placement="top"
            arrowPosition="right"
          >
            <ControlButton
              variant="text"
              size="small"
              data-testid="collapse-all"
              icon={controlsType === 'icon' ? <MinimizeIcon /> : undefined}
              onClick={collapse?.onClick}
              aria-label="Collapse all"
            >
              {controlsType !== 'icon' && (expand?.label || 'Collapse all')}
            </ControlButton>
          </Tooltip>
        ) : null}

        {select ? (
          <ControlButton
            variant="text"
            size="small"
            data-testid="select-all"
            icon={controlsType === 'icon' ? <SelectIcon /> : undefined}
            onClick={select?.onClick}
          >
            {controlsType !== 'icon' && select?.label ? select.label : 'Select all'}
          </ControlButton>
        ) : null}

        {deselect ? (
          <ControlButton
            variant="text"
            size="small"
            data-testid="clear-all"
            icon={controlsType === 'icon' ? <DeselectIcon /> : undefined}
            onClick={deselect?.onClick}
          >
            {controlsType !== 'icon' && deselect?.label ? deselect.label : 'Clear all'}
          </ControlButton>
        ) : null}

        {copy && !codeSnippet?.copy?.hide ? (
          <Tooltip
            tip={translate('codeSnippet.copy.tooltipText', 'Copy to clipboard')}
            placement="top"
            arrowPosition="right"
          >
            <StyledCopyButton
              data={copy.data}
              data-source={copy.dataSource}
              data-hash={copy.dataHash}
              type={controlsType}
              toasterPlacement={copy.toasterPlacement}
              toasterDuration={copy.toasterDuration}
              buttonText={copy.label}
              onCopyClick={() => {
                // If there already is a click handler, events should be handled there, cause they pass additional data
                if (copy?.onClick) {
                  copy?.onClick?.();
                } else {
                  telemetry.sendCopyCodeSnippetClickedMessage([
                    {
                      id: 'copyCodeSnippetButton',
                      object: 'button',
                      uri: 'urn:redocly:redoc:ui:button:copyCodeSnippetButton',
                      snippetType: 'copy',
                    },
                  ]);
                }
              }}
            />
          </Tooltip>
        ) : null}
      </ControlsWrapper>
    </>
  ) : null;

  return children || controls ? (
    <ContainerWrapper
      data-component-name="CodeBlock/CodeBlockControls"
      className={className}
      $isEmptyTitle={isEmptyTitle}
    >
      {children ? children : defaultControls}
    </ContainerWrapper>
  ) : null;
}

const ContainerWrapper = styled.div<{ $isEmptyTitle: boolean }>`
  display: grid;
  flex-direction: row;
  align-items: center;
  gap: var(--spacing-sm);
  font-size: var(--code-block-controls-font-size);
  font-family: var(--code-block-controls-font-family);
  background-color: var(--code-block-controls-bg-color);
  padding: var(--code-block-controls-padding);
  border-bottom: var(--code-block-controls-border);
  line-height: var(--line-height-lg);
  min-height: var(--control-height-base);
  grid-template-columns: 1fr auto;
  z-index: 1;
  ${({ $isEmptyTitle }) =>
    $isEmptyTitle &&
    `
      position: absolute;
      right: 0;
      width: auto;
      border: none;
      background-color: transparent;
      grid-template-columns: 1fr;
      margin: 0;
    `}
`;

const Title = styled.span`
  display: flex;
  align-items: center;
  color: var(--code-block-controls-text-color);
  width: 100%;
  font-weight: var(--code-block-controls-font-weight);
  padding-left: var(--spacing-xs);
`;

const ControlsWrapper = styled.div`
  display: flex;
  text-align: right;
  align-items: center;
  gap: var(--spacing-xxs);
  justify-content: end;
`;

const ControlButton = styled(Button)`
  --button-icon-size: 16px; /* increase icon size for code blocks */
  --button-icon-padding: 3px;
  --button-backdrop-filter: blur(8px); /* backdrop filter when there is text under the button */

  & + & {
    margin-left: 0;
  }
`;

const StyledCopyButton = styled(CopyButton)`
  --button-icon-size: 16px; /* increase icon size for code blocks */
  --button-icon-padding: 3px;
  --button-backdrop-filter: blur(8px);
`;
