'use client';

import React, {
  Children,
  ReactElement,
  ReactNode,
  useState,
} from 'react';
import styles from './CodeSnippet.module.css';

interface MarkdocFenceProps {
  language?: string;
  content?: string;
  className?: string;
}

function isMarkdocElement(
  child: ReactNode
): child is ReactElement<MarkdocFenceProps> {
  return React.isValidElement(child);
}

function CodeSnippetCopyButton({
  copyText,
}: {
  copyText: string;
}) {
  const [copyButtonTooltip, setCopyButtonTooltip] =
    useState<boolean>(false);

  const [showTooltip, setShowTooltip] =
    useState<boolean>(false);

  const handleCopy = () => {
    setCopyButtonTooltip(true);
    setTimeout(() => {
      setCopyButtonTooltip(false);
    }, 1000);

    navigator.clipboard.writeText(copyText ?? '');
  };

  return (
    <div className={styles.copyButtonContainer}>
      <div>
        <div
          className={
            showTooltip
              ? styles.tooltip
              : styles.tooltipHidden
          }
        >
          {copyButtonTooltip ? 'Copied!' : 'Click to Copy'}
        </div>
      </div>
      <button
        className={styles.copyButton}
        onClick={handleCopy}
        onMouseEnter={() => setShowTooltip(true)}
        onMouseLeave={() => setShowTooltip(false)}
      >
        <svg
          xmlns="http://www.w3.org/2000/svg"
          width="16"
          height="16"
          fill="currentColor"
          viewBox="0 0 16 16"
        >
          <path
            fillRule="evenodd"
            d="M10 1.5a.5.5 0 0 0-.5-.5h-3a.5.5 0 0 0-.5.5v1a.5.5 0 0 0 .5.5h3a.5.5 0 0 0 .5-.5v-1Zm-5 0A1.5 1.5 0 0 1 6.5 0h3A1.5 1.5 0 0 1 11 1.5v1A1.5 1.5 0 0 1 9.5 4h-3A1.5 1.5 0 0 1 5 2.5v-1Zm-2 0h1v1A2.5 2.5 0 0 0 6.5 5h3A2.5 2.5 0 0 0 12 2.5v-1h1a2 2 0 0 1 2 2V14a2 2 0 0 1-2 2H3a2 2 0 0 1-2-2V3.5a2 2 0 0 1 2-2Z"
          />
        </svg>
      </button>
    </div>
  );
}

function SnippetLanguageDropdown({
  selectedLanguage,
  snippetLanguages,
  handleSelectChange,
}: {
  selectedLanguage: string;
  snippetLanguages: string[];
  handleSelectChange: (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => void;
}) {
  return (
    <div className={styles.dropdownContainer}>
      <div className={styles.dropdown}>
        <select
          title="Select a language"
          className={styles.dropdownSelect}
          value={selectedLanguage}
          onChange={handleSelectChange}
        >
          {snippetLanguages.map(language => {
            return (
              <option
                key={language}
                value={language}
                className={styles.selectItem}
              >
                {language}
              </option>
            );
          })}
        </select>
      </div>
    </div>
  );
}

export default function CodeSnippet({
  children,
  method,
  heading,
  defaultLanguage,
}: {
  children: ReactNode;
  method?: string;
  heading: string;
  defaultLanguage: string;
}) {
  const methodStyles: { [key: string]: string } = {
    GET: styles.get,
    POST: styles.post,
    PUT: styles.put,
    DELETE: styles.delete,
  };

  const [selectedLanguage, setSelectedLanguage] =
    useState<string>(defaultLanguage);

  const handleSelectChange = (
    e: React.ChangeEvent<HTMLSelectElement>
  ) => {
    setSelectedLanguage(e.target.value);
  };

  const childrenArray = Children.toArray(children);

  const code = childrenArray.find(
    (child): child is ReactElement<MarkdocFenceProps> => {
      if (!isMarkdocElement(child)) return false;
      const { language, className } = child.props;
      return (
        language === selectedLanguage ||
        className === `language-${selectedLanguage}`
      );
    }
  );

  const snippetLanguages = childrenArray
    .map(child => {
      if (isMarkdocElement(child)) {
        const { language, className } = child.props;
        return language || className?.split('-')[1];
      }
      return undefined;
    })
    .filter((l): l is string => typeof l === 'string');

  return (
    <div className={styles.snippetContainer}>
      <div className={styles.snippetHeader}>
        <div className={styles.snippetHeading}>
          {method ? (
            <span className={methodStyles[method]}>
              {method}
            </span>
          ) : null}{' '}
          {heading}
        </div>
        <div className={styles.controlsContainer}>
          {snippetLanguages.length > 1 ? (
            <>
              <SnippetLanguageDropdown
                selectedLanguage={selectedLanguage}
                snippetLanguages={snippetLanguages}
                handleSelectChange={handleSelectChange}
              />
              <div className={styles.spacer} />
            </>
          ) : null}
          <CodeSnippetCopyButton
            copyText={code?.props.content ?? ''}
          />
        </div>
      </div>
      <div className={styles.snippetContent}>
        <pre>{code}</pre>
      </div>
    </div>
  );
}
