import { useEffect, useMemo, useState } from "react"
import type { ComponentProps, ReactNode } from "react"
import { useLexicalComposerContext } from "@lexical/react/LexicalComposerContext"
import { mergeRegister } from "@lexical/utils"
import {
  CAN_REDO_COMMAND,
  CAN_UNDO_COMMAND,
  COMMAND_PRIORITY_LOW,
  SELECTION_CHANGE_COMMAND,
} from "lexical"
import { TooltipProvider } from "@workspace/ui/components/tooltip"
import { cn } from "@workspace/ui/lib/utils"

import { defaultActionState, LexicalActionContext } from "./context"
import { LexicalActionTree } from "./actions-view"
import { useLexicalActions } from "./actions-context"

export type LexicalFixedToolbarProps = ComponentProps<"div">

function LexicalActionRuntimeProvider({ children }: { children: ReactNode }) {
  const [editor] = useLexicalComposerContext()
  const [state, setState] = useState(defaultActionState)
  const context = useMemo(() => ({ editor, state }), [editor, state])

  useEffect(() => {
    const update = () => {
      setState((current) => ({
        ...current,
        revision: current.revision + 1,
      }))
    }
    return mergeRegister(
      editor.registerUpdateListener(update),
      editor.registerCommand(
        SELECTION_CHANGE_COMMAND,
        () => {
          update()
          return false
        },
        COMMAND_PRIORITY_LOW
      ),
      editor.registerCommand(
        CAN_UNDO_COMMAND,
        (canUndo) => {
          setState((current) => ({ ...current, canUndo }))
          return false
        },
        COMMAND_PRIORITY_LOW
      ),
      editor.registerCommand(
        CAN_REDO_COMMAND,
        (canRedo) => {
          setState((current) => ({ ...current, canRedo }))
          return false
        },
        COMMAND_PRIORITY_LOW
      )
    )
  }, [editor])

  return (
    <LexicalActionContext.Provider value={context}>
      <TooltipProvider>{children}</TooltipProvider>
    </LexicalActionContext.Provider>
  )
}

export function LexicalFixedToolbar({
  className,
  children,
  ...props
}: LexicalFixedToolbarProps) {
  const actions = useLexicalActions("toolbar")

  if (actions.length === 0 && children == null) return null

  return (
    <LexicalActionRuntimeProvider>
      <div
        role="toolbar"
        className={cn(
          "flex min-h-11 flex-wrap items-center gap-1 border-b p-1",
          className
        )}
        {...props}
      >
        <LexicalActionTree items={actions} />
        {children}
      </div>
    </LexicalActionRuntimeProvider>
  )
}

export { LexicalActionRuntimeProvider }
