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

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

import { CodeBlock } from '@redocly/theme/components/CodeBlock/CodeBlock';
import { JsonValue } from '@redocly/theme/components/JsonViewer/Helpers';

export type PanelType = 'request' | 'responses' | 'request-samples' | 'response-samples';

export type JsonProps = {
  title?: CodeBlockControlsProps['title'];
  controls?: CodeBlockControlsProps['controls'];
  /* eslint-disable-next-line @typescript-eslint/no-explicit-any */
  data: any;
  className?: string;
  expandLevel: number;
  startLineNumber?: number;
  onCopyClick?: () => void;
  onPanelToggle?: (isExpanded: boolean, panelType?: PanelType) => void;
};

function JsonComponent({
  data,
  expandLevel = 1,
  className,
  onCopyClick,
  onPanelToggle,
  title,
  controls = {},
}: JsonProps): JSX.Element {
  const showFoldingButtons =
    data && Object.values(data).some((value) => typeof value === 'object' && value !== null);

  const [expandAllSignal, setExpandAllSignal] = React.useState<boolean | undefined>(undefined);

  const expandAll = () => {
    setExpandAllSignal(true);
    onPanelToggle?.(true);
    setTimeout(() => {
      setExpandAllSignal(undefined);
    });
  };

  const collapseAll = () => {
    setExpandAllSignal(false);
    onPanelToggle?.(false);
    setTimeout(() => {
      setExpandAllSignal(undefined);
    });
  };

  const source = JSON.stringify(data, null, 2);

  const hasHeader = title || controls;

  return (
    <JsonViewerWrap
      data-testid="json-viewer"
      data-component-name="JsonViewer/JsonViewer"
      className={className}
    >
      <CodeBlock
        header={
          hasHeader
            ? {
                title,
                className: 'code-block-header',
                controls: controls && {
                  ...controls,
                  copy: { ...controls.copy, data, onClick: onCopyClick, handleOutside: true },
                  expand: showFoldingButtons
                    ? { ...controls.expand, onClick: expandAll }
                    : undefined,
                  collapse: showFoldingButtons
                    ? { ...controls.collapse, onClick: collapseAll }
                    : undefined,
                },
              }
            : undefined
        }
        source={source}
      >
        <FoldingWrap>
          <JsonValue
            value={data}
            level={0}
            standalone={true}
            expandAllSignal={expandAllSignal}
            defaultExpandLevel={Math.max(1, expandLevel)}
          />
        </FoldingWrap>
      </CodeBlock>
    </JsonViewerWrap>
  );
}

export const JsonViewer = memo<JsonProps>(JsonComponent);

const FoldingWrap = styled.div`
  position: relative;
`;

export const JsonViewerWrap = styled.div`
  display: flex;
  flex-direction: column;
  flex: 1;

  & > div {
    border: none;
    margin: 0;
  }

  pre {
    contain: content;
    overflow-x: auto;
    position: relative;
    border-radius: 0 0 var(--border-radius) var(--border-radius);
  }

  .code-block-header {
    border-bottom: 0;
    padding-right: var(--spacing-sm);
  }
`;
