import { useScroll, useSize } from 'ahooks';
import { memo, useCallback, useEffect, useMemo, useRef, useState } from 'react';

import { useExternalTextareaObserver } from '@/hooks/useExternalTextareaObserver';

import SyntaxHighlighter from './SyntaxHighlighter';
import grammar from './prompt.tmLanguage.json';
import { themeConfig } from './promptTheme';
import { useStyles } from './style';

const options: any = {
  langs: [
    {
      aliases: ['prompt'],
      grammar,
      id: 'prompt',
      scopeName: 'source.prompt',
    },
  ],
  themes: [themeConfig(true), themeConfig(false)],
};

interface AppProps {
  parentId: string;
}

const App = memo<AppProps>(({ parentId }) => {
  const ref: any = useRef(null);
  const [prompt, setPrompt] = useState<string>('');
  const { styles, theme } = useStyles();
  const nativeTextareaValue = useExternalTextareaObserver(`${parentId} label textarea`);
  const nativeTextarea = useMemo(
    () => gradioApp().querySelector(`${parentId} label textarea`) as HTMLTextAreaElement,
    [parentId],
  );
  const size = useSize(nativeTextarea);
  const scroll = useScroll(nativeTextarea);

  const handlePromptChange = useCallback((event: any) => {
    setPrompt(event.target.value);
  }, []);

  useEffect(() => {
    ref.current.scroll(0, scroll?.top || 0);
  }, [scroll?.top]);

  useEffect(() => {
    nativeTextarea.addEventListener('change', handlePromptChange);
    return () => {
      nativeTextarea.removeEventListener('change', handlePromptChange);
    };
  }, []);

  useEffect(() => {
    if (theme) {
      nativeTextarea.style.color = 'transparent';
      nativeTextarea.style.caretColor = theme.colorSuccess;
    }
  }, [theme]);

  useEffect(() => {
    setPrompt(nativeTextareaValue);
  }, [nativeTextareaValue]);

  return (
    <div
      className={styles.container}
      data-code-type="highlighter"
      ref={ref}
      style={{ height: size?.height, width: size?.width }}
    >
      <SyntaxHighlighter language="prompt" options={options}>
        {prompt.trim()}
      </SyntaxHighlighter>
    </div>
  );
});

export default App;
