'use client';

import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { LexicalComposer } from '@lexical/react/LexicalComposer';
import { RichTextPlugin } from '@lexical/react/LexicalRichTextPlugin';
import { ContentEditable } from '@lexical/react/LexicalContentEditable';
import { LexicalErrorBoundary } from '@lexical/react/LexicalErrorBoundary';
import { HistoryPlugin } from '@lexical/react/LexicalHistoryPlugin';
import { OnChangePlugin } from '@lexical/react/LexicalOnChangePlugin';
import { ListPlugin } from '@lexical/react/LexicalListPlugin';
import { LinkPlugin } from '@lexical/react/LexicalLinkPlugin';
import { HeadingNode, QuoteNode, $createHeadingNode } from '@lexical/rich-text';
import { ListItemNode, ListNode, INSERT_ORDERED_LIST_COMMAND, INSERT_UNORDERED_LIST_COMMAND } from '@lexical/list';
import { LinkNode, TOGGLE_LINK_COMMAND } from '@lexical/link';
import {
  $getRoot,
  $createParagraphNode,
  EditorState,
  LexicalEditor as LexicalEditorInstance,
  FORMAT_TEXT_COMMAND,
  $isElementNode,
  ElementNode,
  $getSelection,
  $isRangeSelection,
  $createParagraphNode as createParagraph,
} from 'lexical';
import { $generateHtmlFromNodes, $generateNodesFromDOM } from '@lexical/html';
import { useLexicalComposerContext } from '@lexical/react/LexicalComposerContext';

const EMPTY_EDITOR_STATE = JSON.stringify({
  root: {
    children: [
      {
        children: [],
        direction: 'ltr',
        format: '',
        indent: 0,
        type: 'paragraph',
        version: 1,
      },
    ],
    direction: 'ltr',
    format: '',
    indent: 0,
    type: 'root',
    version: 1,
  },
});

const editorTheme = {
  paragraph: 'lex-paragraph',
  heading: {
    h1: 'lex-h1',
    h2: 'lex-h2',
    h3: 'lex-h3',
    h4: 'lex-h4',
  },
  list: {
    ul: 'lex-ul',
    ol: 'lex-ol',
    listitem: 'lex-li',
  },
  link: 'lex-link',
  text: {
    bold: 'lex-bold',
    italic: 'lex-italic',
    underline: 'lex-underline',
  },
};

function makeConfig(disabled: boolean) {
  return {
    namespace: 'MDVCmsEditor',
    nodes: [HeadingNode, QuoteNode, ListNode, ListItemNode, LinkNode],
    editorState: EMPTY_EDITOR_STATE,
    editable: !disabled,
    onError(error: Error) {
      throw error;
    },
    theme: editorTheme,
  };
}

type FormatState = { bold: boolean; italic: boolean; underline: boolean };

function readFormatFromDom(): FormatState {
  if (typeof window === 'undefined') return { bold: false, italic: false, underline: false };
  const domSel = window.getSelection?.();
  let bold = false;
  let italic = false;
  let underline = false;
  if (domSel && domSel.rangeCount > 0) {
    let node: Node | null = domSel.getRangeAt(0).startContainer;
    while (node && node !== document.body) {
      if (node instanceof HTMLElement) {
        const fw = node.style?.fontWeight;
        if (node.tagName === 'B' || node.tagName === 'STRONG' || fw === 'bold' || fw === '700') bold = true;
        if (node.tagName === 'I' || node.tagName === 'EM') italic = true;
        if (node.tagName === 'U' || node.style?.textDecoration?.includes('underline')) underline = true;
      }
      node = node.parentNode;
    }
  }
  return { bold, italic, underline };
}

function ToolbarButton({
  active,
  disabled,
  onClick,
  title,
  children,
}: {
  active?: boolean;
  disabled?: boolean;
  onClick: (e: React.MouseEvent) => void;
  title: string;
  children: React.ReactNode;
}) {
  return (
    <button
      type="button"
      disabled={disabled}
      onMouseDown={(e) => e.preventDefault()}
      onClick={onClick}
      title={title}
      aria-label={title}
      className={`px-2.5 py-1.5 text-sm font-medium rounded-md transition-colors ${
        active ? 'bg-[#2D6A4F] text-white' : 'text-gray-700 hover:bg-gray-100'
      } ${disabled ? 'opacity-40 cursor-not-allowed' : 'cursor-pointer'}`}
    >
      {children}
    </button>
  );
}

function Toolbar({ disabled }: { disabled?: boolean }) {
  const [editor] = useLexicalComposerContext();
  const [active, setActive] = useState<FormatState>({ bold: false, italic: false, underline: false });

  useEffect(() => {
    return editor.registerUpdateListener(() => {
      // Defer to next microtask so React state updates are batched inside the editor's update loop.
      queueMicrotask(() => setActive(readFormatFromDom()));
    });
  }, [editor]);

  const setBlockType = (type: 'paragraph' | 'h2' | 'h3') => {
    editor.update(() => {
      const selection = $getSelection();
      if (!$isRangeSelection(selection)) return;
      const anchor = selection.anchor.getNode();
      let target: ElementNode | null = anchor.getParent();
      while (target && target.getType() !== 'paragraph' && target.getType() !== 'heading') {
        target = target.getParent();
      }
      if (!target) return;
      const currentType = target.getType();
      if (type === 'paragraph') {
        if (currentType === 'heading') {
          const para = createParagraph();
          para.append(...target.getChildren());
          target.replace(para);
        }
      } else if (currentType === 'paragraph') {
        const heading = $createHeadingNode(type);
        heading.append(...target.getChildren());
        target.replace(heading);
      } else if (currentType === 'heading') {
        // Re-create the heading so the new tag is honoured (ElementNode type is immutable).
        const heading = $createHeadingNode(type);
        heading.append(...target.getChildren());
        target.replace(heading);
      }
    });
  };

  return (
    <div className="flex flex-wrap gap-1 border-b border-gray-200 p-2 bg-gray-50 rounded-t-xl">
      <ToolbarButton
        disabled={disabled}
        onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'bold')}
        title="Negrita (Ctrl+B)"
        active={active.bold}
      >
        <span className="font-bold">B</span>
      </ToolbarButton>
      <ToolbarButton
        disabled={disabled}
        onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'italic')}
        title="Cursiva (Ctrl+I)"
        active={active.italic}
      >
        <span className="italic">I</span>
      </ToolbarButton>
      <ToolbarButton
        disabled={disabled}
        onClick={() => editor.dispatchCommand(FORMAT_TEXT_COMMAND, 'underline')}
        title="Subrayado (Ctrl+U)"
        active={active.underline}
      >
        <span className="underline">U</span>
      </ToolbarButton>
      <div className="w-px bg-gray-300 mx-1 self-stretch" />
      <ToolbarButton
        disabled={disabled}
        onClick={() => setBlockType('h2')}
        title="Encabezado 2"
      >
        <span className="text-xs">H2</span>
      </ToolbarButton>
      <ToolbarButton
        disabled={disabled}
        onClick={() => setBlockType('h3')}
        title="Encabezado 3"
      >
        <span className="text-xs">H3</span>
      </ToolbarButton>
      <ToolbarButton
        disabled={disabled}
        onClick={() => setBlockType('paragraph')}
        title="Párrafo normal"
      >
        <span className="text-xs">¶</span>
      </ToolbarButton>
      <div className="w-px bg-gray-300 mx-1 self-stretch" />
      <ToolbarButton
        disabled={disabled}
        onClick={() => editor.dispatchCommand(INSERT_UNORDERED_LIST_COMMAND, undefined)}
        title="Lista con viñetas"
      >
        •
      </ToolbarButton>
      <ToolbarButton
        disabled={disabled}
        onClick={() => editor.dispatchCommand(INSERT_ORDERED_LIST_COMMAND, undefined)}
        title="Lista numerada"
      >
        1.
      </ToolbarButton>
      <ToolbarButton
        disabled={disabled}
        onClick={() => {
          if (typeof window === 'undefined') return;
          const url = window.prompt('URL del enlace (vacío para quitar):', 'https://');
          if (url === null) return;
          editor.dispatchCommand(TOGGLE_LINK_COMMAND, url === '' ? null : url);
        }}
        title="Insertar / quitar enlace"
      >
        🔗
      </ToolbarButton>
    </div>
  );
}

function InitialHtmlPlugin({ initialHtml }: { initialHtml: string }) {
  const [editor] = useLexicalComposerContext();

  useEffect(() => {
    let currentHtml = '';
    editor.getEditorState().read(() => {
      currentHtml = $generateHtmlFromNodes(editor, null);
    });
    if (currentHtml.trim() === initialHtml.trim()) return;

    editor.update(() => {
      const root = $getRoot();
      root.clear();
      if (!initialHtml.trim()) return;
      const parser = new DOMParser();
      const domDoc = parser.parseFromString(`<div>${initialHtml}</div>`, 'text/html');
      const nodes = $generateNodesFromDOM(editor, domDoc.body);
      const ensured: ElementNode[] = [];
      nodes.forEach((node) => {
        if ($isElementNode(node)) {
          ensured.push(node);
        } else {
          const p = $createParagraphNode();
          p.append(node as never);
          ensured.push(p);
        }
      });
      if (ensured.length === 0) ensured.push($createParagraphNode());
      ensured.forEach((n) => root.append(n));
    });
  }, [editor, initialHtml]);

  return null;
}

export interface LexicalEditorProps {
  value: string;
  onChange: (html: string) => void;
  placeholder?: string;
  disabled?: boolean;
  className?: string;
}

export default function LexicalEditor({
  value,
  onChange,
  placeholder = 'Escribe el contenido…',
  disabled,
  className = '',
}: LexicalEditorProps) {
  const handleChange = useCallback(
    (editorState: EditorState, _editor: LexicalEditorInstance) => {
      editorState.read(() => {
        const html = $generateHtmlFromNodes(_editor, null);
        onChange(html);
      });
    },
    [onChange],
  );

  const config = useMemo(() => makeConfig(!!disabled), [disabled]);

  return (
    <div className={`border border-gray-300 rounded-xl overflow-hidden bg-white ${className}`}>
      <LexicalComposer initialConfig={config}>
        <Toolbar disabled={disabled} />
        <div className="relative">
          <RichTextPlugin
            contentEditable={
              <ContentEditable
                className="min-h-[220px] px-4 py-3 text-sm text-gray-800 focus:outline-none prose-sm max-w-none"
                aria-label="Contenido CMS"
              />
            }
            placeholder={
              <div className="absolute top-3 left-4 text-sm text-gray-400 pointer-events-none select-none">
                {placeholder}
              </div>
            }
            ErrorBoundary={LexicalErrorBoundary}
          />
        </div>
        <HistoryPlugin />
        <ListPlugin />
        <LinkPlugin />
        <InitialHtmlPlugin initialHtml={value} />
        <OnChangePlugin onChange={handleChange} ignoreSelectionChange />
      </LexicalComposer>
      <style jsx global>{`
        .lex-paragraph { margin: 0 0 0.5rem 0; }
        .lex-paragraph:last-child { margin-bottom: 0; }
        .lex-h2 { font-size: 1.5rem; font-weight: 700; margin: 1rem 0 0.5rem; color: #111827; }
        .lex-h3 { font-size: 1.25rem; font-weight: 600; margin: 0.75rem 0 0.5rem; color: #111827; }
        .lex-h4 { font-size: 1.05rem; font-weight: 600; margin: 0.5rem 0 0.25rem; color: #111827; }
        .lex-ul { list-style: disc; padding-left: 1.5rem; margin: 0.25rem 0; }
        .lex-ol { list-style: decimal; padding-left: 1.5rem; margin: 0.25rem 0; }
        .lex-li { margin: 0.125rem 0; }
        .lex-link { color: #2D6A4F; text-decoration: underline; }
        .lex-bold { font-weight: 700; }
        .lex-italic { font-style: italic; }
        .lex-underline { text-decoration: underline; }
      `}</style>
    </div>
  );
}