import { useEffect, useMemo, useReducer, type ReactNode } from 'react'
import { EditorContent, useEditor } from '@tiptap/react'
import { DefaultToolbar, type RichTextEditorToolbarState } from './DefaultToolbar'
import {
  createDefaultExtensions,
  type EditorExtensionConfig,
} from './extensions'

export interface RichTextEditorProps {
  value: string
  onChange: (next: string) => void
  dir?: 'ltr' | 'rtl'
  'aria-label': string                   // a11y HARD FLOOR — REQUIRED: editor sets role=textbox, so an accessible name is mandatory (WCAG 4.1.2)
  extensions?: EditorExtensionConfig
  readOnly?: boolean
  className?: string
  renderToolbar?: (state: RichTextEditorToolbarState) => ReactNode
}

function useToolbarState(editor: ReturnType<typeof useEditor>): RichTextEditorToolbarState {
  const [, rerender] = useReducer((n: number) => n + 1, 0)

  useEffect(() => {
    if (!editor) return
    const update = () => rerender()
    editor.on('selectionUpdate', update)
    editor.on('transaction', update)
    return () => {
      editor.off('selectionUpdate', update)
      editor.off('transaction', update)
    }
  }, [editor])

  return {
    editor,
    isBold: editor?.isActive('bold') ?? false,
    isItalic: editor?.isActive('italic') ?? false,
    isH2: editor?.isActive('heading', { level: 2 }) ?? false,
    isBullet: editor?.isActive('bulletList') ?? false,
  }
}

export function RichTextEditor({
  value,
  onChange,
  dir = 'ltr',
  'aria-label': ariaLabel,
  extensions,
  readOnly = false,
  className,
  renderToolbar,
}: RichTextEditorProps) {
  const resolvedExtensions = useMemo(
    () => extensions?.extensions ?? createDefaultExtensions(),
    [extensions],
  )

  const editor = useEditor(
    {
      extensions: resolvedExtensions,
      content: value,
      editable: !readOnly,
      immediatelyRender: false,
      onUpdate: ({ editor: ed }) => onChange(ed.getHTML()),
      editorProps: {
        attributes: {
          dir,
          role: 'textbox',
          'aria-multiline': 'true',
          'aria-label': ariaLabel,
        },
      },
    },
    [resolvedExtensions],
  )

  useEffect(() => {
    if (!editor) return
    if (value !== editor.getHTML()) {
      editor.commands.setContent(value, false)
    }
  }, [editor, value])

  useEffect(() => {
    if (!editor) return
    editor.setEditable(!readOnly)
  }, [editor, readOnly])

  useEffect(() => {
    if (!editor) return
    const root = editor.view.dom as HTMLElement
    root.setAttribute('dir', dir)
    root.setAttribute('aria-label', ariaLabel)
  }, [editor, dir, ariaLabel])

  const toolbarState = useToolbarState(editor)

  return (
    <div className={className}>
      {renderToolbar ? renderToolbar(toolbarState) : <DefaultToolbar {...toolbarState} />}
      <EditorContent editor={editor} />
    </div>
  )
}
