import React, { useEffect, useRef, useState } from 'react';
import styled, { css } from 'styled-components';

import type { JSX } from 'react';
import type { CodeWalkthroughFile } from '@redocly/config';

import { useThemeHooks, useRenderableFiles, type RenderableFile } from '@redocly/theme/core/hooks';
import { OverflowMenuVerticalIcon } from '@redocly/theme/icons/OverflowMenuVerticalIcon/OverflowMenuVerticalIcon';
import { Dropdown } from '@redocly/theme/components/Dropdown/Dropdown';
import { DropdownMenu } from '@redocly/theme/components/Dropdown/DropdownMenu';
import { DropdownMenuItem } from '@redocly/theme/components/Dropdown/DropdownMenuItem';
import { DownloadIcon } from '@redocly/theme/icons/DownloadIcon/DownloadIcon';
import { Button } from '@redocly/theme/components/Button/Button';

export type CodePanelHeaderProps = {
  files: CodeWalkthroughFile[];
  handleTabSwitch: (name: string) => void;
  activeTabName: string;
  onDownloadCode: () => void;
};

export function CodePanelHeader({
  files,
  handleTabSwitch,
  activeTabName,
  onDownloadCode,
}: CodePanelHeaderProps): JSX.Element {
  const renderableFiles = useRenderableFiles(files);
  const { useTranslate } = useThemeHooks();
  const { translate } = useTranslate();
  const tabRefs = useRef<HTMLButtonElement[]>([]);
  const tabsWrapperRef = useRef<HTMLDivElement>(null);
  const [hiddenFiles, setHiddenFiles] = useState<RenderableFile[]>([]);

  useEffect(() => {
    const activeTab = tabRefs.current.find((tab) => tab?.dataset.name === activeTabName);
    const tabsWrapper = tabsWrapperRef.current;

    if (activeTab && tabsWrapper) {
      const { left: wrapperLeft, right: wrapperRight } = tabsWrapper.getBoundingClientRect();
      const { left: tabLeft, right: tabRight } = activeTab.getBoundingClientRect();
      const tabHidden = tabLeft < wrapperLeft || tabRight > wrapperRight;

      if (tabHidden) {
        activeTab.scrollIntoView({ block: 'nearest', inline: 'nearest' });
      }
    }

    const calculateHiddenFiles = () => {
      if (!tabsWrapperRef.current) return;
      const { left: wrapperLeft, right: wrapperRight } =
        tabsWrapperRef.current.getBoundingClientRect();

      const hidden: RenderableFile[] = [];

      for (let i = 0; i < renderableFiles.length; i++) {
        const tab = tabRefs.current[i];
        if (!tab) continue;

        const { left: tabLeft, right: tabRight } = tab.getBoundingClientRect();
        const visible = tabLeft >= wrapperLeft && tabRight <= wrapperRight;

        if (!visible) {
          hidden.push(renderableFiles[i]);
        }
      }

      setHiddenFiles(hidden);
    };

    calculateHiddenFiles();
    window.addEventListener('resize', calculateHiddenFiles);
    return () => window.removeEventListener('resize', calculateHiddenFiles);
  }, [activeTabName, files, renderableFiles]);

  return (
    <CodePanelHeaderWrapper data-component-name="Markdoc/CodeWalkthrough/CodePanelHeader">
      <TabsWrapper ref={tabsWrapperRef}>
        <Tabs>
          {renderableFiles.map(
            ({ path, basename, fileIcon, parentFolder, isNameDuplicate, inRootDir }, i) => {
              return (
                <Tab
                  ref={(el: HTMLButtonElement | null) => {
                    tabRefs.current[i] = el as HTMLButtonElement;
                  }}
                  data-name={path}
                  active={path === activeTabName}
                  key={i}
                  onClick={() => handleTabSwitch(path)}
                >
                  {fileIcon}
                  {basename}
                  {isNameDuplicate && !inRootDir ? <Dirname>{parentFolder}</Dirname> : null}
                </Tab>
              );
            },
          )}
        </Tabs>
        <Gradient />
      </TabsWrapper>

      <ActionBar>
        {hiddenFiles.length ? (
          <Dropdown trigger={<StyledOverflowMenuVerticalIcon size="14px" />} alignment="end">
            <StyledDropdownMenu>
              {hiddenFiles.map(
                ({ path, basename, fileIcon, isNameDuplicate, inRootDir, parentFolder }, i) => {
                  return (
                    <DropdownMenuItem
                      active={path === activeTabName}
                      key={i}
                      onAction={() => handleTabSwitch(path)}
                      prefix={fileIcon}
                      content={
                        isNameDuplicate && !inRootDir ? `${parentFolder}/${basename}` : basename
                      }
                    />
                  );
                },
              )}
            </StyledDropdownMenu>
          </Dropdown>
        ) : null}

        <Button variant="text" icon={<DownloadIcon />} onClick={onDownloadCode} size="small">
          {translate('codeWalkthrough.download', 'Download')}
        </Button>
      </ActionBar>
    </CodePanelHeaderWrapper>
  );
}

const CodePanelHeaderWrapper = styled.div`
  display: flex;
  align-items: center;
  justify-content: space-between;

  padding: var(--spacing-xs) var(--spacing-xs) var(--spacing-xs) var(--spacing-sm);
  max-width: 100%;
`;

const TabsWrapper = styled.div`
  display: flex;
  position: relative;
  min-width: 0;
`;

const Gradient = styled.div`
  position: absolute;
  right: 0;
  width: var(--spacing-base);
  height: var(--code-panel-header-height);
  background: var(--bg-raised-gradient);
`;

const Tabs = styled.div`
  display: flex;
  overflow-x: hidden;
  padding-right: var(--spacing-base);

  &::-webkit-scrollbar {
    display: none;
  }
`;

const Dirname = styled.span`
  font-size: var(--font-size-sm);
  color: var(--text-color-description);
`;

const ActionBar = styled.div`
  display: flex;
`;

const Tab = styled.button<{ active: boolean }>`
  --icon-width: 16px;
  --icon-height: 16px;

  display: inline-flex;
  align-items: center;
  padding: 0 var(--spacing-sm);
  background-color: transparent;
  height: var(--code-panel-header-height);
  border-radius: var(--border-radius);
  cursor: pointer;
  gap: var(--spacing-xs);
  color: var(--text-color-secondary);
  white-space: nowrap;
  scroll-margin-right: var(--spacing-base);
  ${({ active }) =>
    active
      ? css`
          color: var(--text-color-primary);
          background-color: var(--tab-bg-color-filled);
        `
      : css`
          &:hover {
            color: var(--text-color-primary);
          }
        `}
`;
// eslint-disable-next-line no-warning-comments
// code-walk-todo: figure it our why we could not do it differently
const StyledDropdownMenu = styled(DropdownMenu)`
  --md-list-left-padding: var(--dropdown-menu-padding);
`;

const StyledOverflowMenuVerticalIcon = styled(OverflowMenuVerticalIcon)`
  && {
    outline: none;
    box-sizing: content-box;
    padding: 5px;
  }
`;
