'use client';
import { useState, useRef } from 'react';
import {
  useEditor,
  EditorContent,
  JSONContent,
  generateJSON,
  generateHTML
} from '@tiptap/react';
import StarterKit from '@tiptap/starter-kit';
import { cn } from '@/lib/utils/cn';
import {
  WidgetBlockNode,
  WidgetPlaceholderBlock
} from '../tiptap-node/widget/widget-block-extension';
import {
  WidgetInlineNode,
  WidgetPlaceholderInline
} from '../tiptap-node/widget/widget-inline-extension';
import { TableKit } from '@tiptap/extension-table';
import TextAlign from '@tiptap/extension-text-align';
import { Color } from '@tiptap/extension-text-style';
import TiptapToolbar from '../components/tiptap-toolbar';
import { CustomTextStyle } from '../components/node-textstyle';
import { ImageWithAlign } from '../components/node-image';
import {
  replaceWidgetsWithPlaceholders,
  restoreWidgetsFromPlaceholders
} from '../tiptap-renderer/renderer-helpers';
import { Textarea } from '@/components/ui/textarea';
import { SquareCode, SquarePen } from 'lucide-react';
import { IframeNode } from '../components/node-iframe';
import prettier from 'prettier/standalone';
import parserHtml from 'prettier/plugins/html';

interface TiptapEditorProps {
  content?: JSONContent;
  className?: string;
  hideWidgets?: boolean;
  onChange?: (content: JSONContent) => void;
}

const extensions = [
  StarterKit,
  CustomTextStyle,
  Color,
  WidgetBlockNode,
  WidgetPlaceholderBlock,
  WidgetInlineNode,
  WidgetPlaceholderInline,
  TableKit.configure({
    table: { resizable: true }
  }),
  TextAlign.configure({
    types: ['heading', 'paragraph', 'tableCell', 'tableHeader']
  }),
  ImageWithAlign,
  IframeNode
];

const formattingRegex =
  /(<\/(p|div|section|article|h[1-6]|ul|ol|table|blockquote|figure|widget-[^>]+)>|<img[^>]*\/?>)\n/g;

export default function TiptapEditor({
  content = {},
  onChange,
  className,
  hideWidgets = false
}: TiptapEditorProps) {
  const [isSourceMode, setIsSourceMode] = useState(false);
  const [htmlSource, setHtmlSource] = useState('');
  const widgetCacheRef = useRef<Map<string, JSONContent>>(new Map());

  const editor = useEditor(
    {
      extensions,
      content,
      onUpdate: ({ editor }) => {
        const json = editor.getJSON();
        onChange?.(json);
      },
      editorProps: {
        attributes: {
          class:
            'prose prose-sm sm:prose lg:prose-lg xl:prose-2xl mx-auto focus:outline-none min-h-[200px] p-4 tip-tap'
        }
      },
      immediatelyRender: false
    },
    []
  );

  const handleEnterSource = async () => {
    if (!editor) return;

    const cache = new Map<string, JSONContent>();

    const replacedJSON = replaceWidgetsWithPlaceholders(
      editor.getJSON(),
      cache
    );
    widgetCacheRef.current = cache;

    const html = generateHTML(replacedJSON, extensions);

    const formatted = await prettier.format(html, {
      parser: 'html',
      plugins: [parserHtml],
      tabWidth: 2,
      printWidth: 100,
      htmlWhitespaceSensitivity: 'ignore',
      bracketSameLine: false
    });

    setHtmlSource(formatted.replace(formattingRegex, '$1\n\n'));
    setIsSourceMode(true);
  };

  const handleExitSource = () => {
    if (!editor) return;
    handleTextChange(htmlSource);
    setIsSourceMode(false);

    try {
      const json = generateJSON(htmlSource, extensions);
      const restoredJSON = restoreWidgetsFromPlaceholders(
        json,
        widgetCacheRef.current
      );

      editor.commands.setContent(restoredJSON, {
        emitUpdate: true
      });

      setIsSourceMode(false);
    } catch (e) {
      console.error('HTML parse error', e);
    }
  };

  const handleTextChange = (value: string) => {
    if (!editor || !value) return;
    setHtmlSource(value);
    try {
      const json = generateJSON(value, extensions);
      const restoredJSON = restoreWidgetsFromPlaceholders(
        json,
        widgetCacheRef.current
      );
      editor.commands.setContent(restoredJSON, {});
    } catch (e) {
      console.error('HTML parse error', e);
    }
  };

  if (!editor) {
    return null;
  }

  return (
    <div className={cn('overflow-hidden rounded-lg border', className)}>
      <TiptapToolbar editor={editor} hideWidgets={hideWidgets} />
      <div className='flex justify-end'>
        <button
          type='button'
          title={isSourceMode ? 'Show editor' : 'Show source code'}
          onClick={() =>
            isSourceMode ? handleExitSource() : handleEnterSource()
          }
          className='hover:text-client-red p-2 text-sm focus:outline-none'
        >
          {isSourceMode ? (
            <SquarePen className='size-6' />
          ) : (
            <SquareCode className='size-6' />
          )}
        </button>
      </div>
      <div className={cn('hidden', isSourceMode && 'block')}>
        <Textarea
          value={htmlSource}
          onChange={(e) => handleTextChange(e.target.value)}
          className='max-h-200 min-h-100 resize-none overflow-auto border-0 font-mono shadow-none focus:ring-0'
        />
      </div>

      <div className={cn('block', isSourceMode && 'hidden')}>
        <EditorContent
          editor={editor}
          className='max-h-screen min-h-100 overflow-auto font-serif'
        />
      </div>
    </div>
  );
}
