import React from 'react';

import hljs from 'highlight.js/lib/core';
import bash from 'highlight.js/lib/languages/bash';
import js from 'highlight.js/lib/languages/javascript';
import json from 'highlight.js/lib/languages/json';
import markdown from 'highlight.js/lib/languages/markdown';
import python from 'highlight.js/lib/languages/python';
import xml from 'highlight.js/lib/languages/xml';
import { BaseProps } from '@digigov/react-core/Base';
import CodeBlockContainer from '@digigov/react-core/CodeBlockContainer';
import CodeBlockContent from '@digigov/react-core/CodeBlockContent';
import CodeBlockHeader from '@digigov/react-core/CodeBlockHeader';
import { CopyToClipboard } from '@digigov/ui/feedback';
import { PhaseBannerTag } from '@digigov/ui/feedback/PhaseBanner';
import { Button } from '@digigov/ui/form/Button';

export interface CodeBlockProps extends BaseProps<'div'> {
  language?: 'javascript' | 'bash' | 'xml' | 'python' | 'markdown' | 'json';
  copyToClipboard?: boolean;
  highlighted?: boolean;
  showLineNumbers?: boolean;
  phaseBannerTagName?: string;
  highlightLines?: number[];
}

const languageMap = {
  javascript: js,
  python: python,
  bash: bash,
  xml: xml,
  markdown: markdown,
  json: json,
};

const addLineNumbers = (code: string, highlightLines: number[]): string => {
  return code
    .split('\n')
    .map((line, index) => {
      const isHighlighted = highlightLines.includes(index + 1);
      const lineClass = isHighlighted ? 'ds-code--highlighted-line' : '';
      return `<span class="ds-code--line-number">${index + 1}</span> <span class="${lineClass}">${line}</span>`;
    })
    .join('\n');
};

export const CodeBlock = React.forwardRef<HTMLDivElement, CodeBlockProps>(
  function CodeBlock(
    {
      children,
      language,
      copyToClipboard,
      highlighted,
      showLineNumbers,
      phaseBannerTagName,
      highlightLines,
      ...props
    },
    ref
  ) {
    const Tag = 'span';
    const codeString = typeof children === 'string' ? children : '';
    let displayingCode = codeString;

    if (highlighted && codeString) {
      try {
        hljs.configure({ classPrefix: 'ds-code--' });
        let highlightedCode = hljs.highlightAuto(codeString).value;
        if (language) {
          hljs.registerLanguage(language, languageMap[language]);
          highlightedCode = hljs.highlight(codeString, {
            language: language,
          }).value;
        }
        displayingCode = showLineNumbers
          ? addLineNumbers(highlightedCode, highlightLines || [])
          : highlightedCode;
      } catch (error) {
        console.error('Highlighting failed:', error);
      }
    }

    return (
      <CodeBlockContainer ref={ref} {...props}>
        <CodeBlockHeader
          justify={
            phaseBannerTagName && copyToClipboard ? 'space-between' : 'end'
          }
        >
          {phaseBannerTagName && (
            <PhaseBannerTag>{phaseBannerTagName}</PhaseBannerTag>
          )}
          {copyToClipboard && (
            <CopyToClipboard
              dense
              text={codeString}
              variant="tooltip"
              tooltipAlign="right"
              message="Copied!"
            >
              <Button dense color="secondary">
                Copy
              </Button>
            </CopyToClipboard>
          )}
        </CodeBlockHeader>
        <CodeBlockContent className={`language-${language}`}>
          {highlighted && codeString ? (
            <Tag
              dangerouslySetInnerHTML={{
                __html: displayingCode,
              }}
            />
          ) : (
            children
          )}
        </CodeBlockContent>
      </CodeBlockContainer>
    );
  }
);

export * from '@digigov/react-core/CodeBlockContent';
export * from '@digigov/react-core/CodeBlockHeader';
export * from '@digigov/react-core/CodeBlockContainer';
export default CodeBlock;
