'use client'

import type * as React from 'react'
import type { ContentEditorSelectionRequest } from '@admin/utils/editor/content-editor-selection-request'
import type { MarkdownHeadingLevel } from '@admin/utils/editor/markdown-heading-level'
import type { MarkdownListType } from '@admin/utils/editor/markdown-list-type'
import { SourceColorHighlightPopover } from '@admin/components/custom/content-editor/tiptap-ui/color-highlight-popover'
import { LinkControlPopover } from '@admin/components/custom/content-editor/tiptap-ui/link-popover'
import { Button } from '@admin/components/ui/button'
import { DropdownMenuItem } from '@admin/components/ui/dropdown-menu'
import { Separator } from '@admin/components/ui/separator'
import { useContentEditorSourceMode } from '@admin/hooks/content-editor/use-content-editor-source-mode'
import { getContentEditorHighlightColorName } from '@admin/utils/editor/get-content-editor-highlight-color-name'
import { MARKDOWN_HEADING_OPTIONS } from '@admin/utils/editor/markdown-heading-options'
import { MARKDOWN_LIST_OPTIONS } from '@admin/utils/editor/markdown-list-options'
import { cn } from '@admin/utils/shared/cn'
import CodeMirror from '@uiw/react-codemirror'
import {
  TextQuoteIcon as BlockquoteIcon,
  BoldIcon,
  Code2Icon,
  SquareCodeIcon as CodeBlockIcon,
  Heading5Icon as HeadingFiveIcon,
  Heading4Icon as HeadingFourIcon,
  HeadingIcon,
  Heading6Icon as HeadingSixIcon,
  Heading3Icon as HeadingThreeIcon,
  Heading2Icon as HeadingTwoIcon,
  ImagePlusIcon,
  ItalicIcon,
  ListIcon,
  ListOrderedIcon,
  ListTodoIcon,
  Minus,
  Redo2Icon,
  StrikethroughIcon as StrikeIcon,
  UnderlineIcon,
  Undo2Icon
} from 'lucide-react'
import { EditorToolbar } from './editor-toolbar'
import { MathPopoverButton } from './math-popover'
import { SourceModeDropdownButton } from './source-mode-dropdown-button'
import { TableButton } from './table-button'

type SvgIcon = React.ComponentType<{ className?: string }>
const HEADING_ICONS: Record<MarkdownHeadingLevel, SvgIcon> = {
  2: HeadingTwoIcon,
  3: HeadingThreeIcon,
  4: HeadingFourIcon,
  5: HeadingFiveIcon,
  6: HeadingSixIcon
}

const LIST_ICONS: Record<MarkdownListType, SvgIcon> = {
  bullet: ListIcon,
  ordered: ListOrderedIcon,
  task: ListTodoIcon
}

export interface SourceModeProps {
  value?: string
  onChange?: (value: string) => void
  placeholder?: string
  disabled?: boolean
  className?: string
  toolbarEnd?: React.ReactNode
  selectionRequest?: ContentEditorSelectionRequest | null
  onSelectionChange?: (offset: number) => void
}

export function SourceMode({
  value = '',
  onChange,
  placeholder,
  disabled = false,
  className,
  toolbarEnd,
  selectionRequest,
  onSelectionChange
}: SourceModeProps) {
  const {
    applyBlockquote,
    applyBold,
    applyCode,
    applyHeading,
    applyHighlight,
    applyItalic,
    applyList,
    applyStrike,
    applyUnderline,
    canRedoMarkdownChange,
    canUndoMarkdownChange,
    codeMirrorExtensions,
    editorRef,
    editorTheme,
    handleCreateEditor,
    handleEditorChange,
    handleMarkdownLinkPopoverOpenChange,
    insertCodeBlock,
    insertDivider,
    insertMath,
    insertTable,
    isMarkdownLinkActive,
    markdownLinkUrl,
    openMediaGalleryAtCursor,
    redoMarkdownChange,
    removeHighlight,
    removeMarkdownLink,
    setMarkdownLink,
    setMarkdownLinkUrl,
    undoMarkdownChange
  } = useContentEditorSourceMode({
    value,
    onChange,
    disabled,
    selectionRequest,
    onSelectionChange
  })

  return (
    <div
      className={cn(
        'content-editor-wrapper relative flex max-h-[90vh] min-h-[240px] resize-y flex-col overflow-hidden rounded-md border bg-background',
        { 'opacity-50': disabled },
        className
      )}
    >
      <EditorToolbar ariaLabel="Markdown editor toolbar" className="shrink-0">
        <div className="flex h-full min-w-0 flex-1 items-center overflow-x-auto">
          <div className="flex items-center gap-0.5">
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              onClick={undoMarkdownChange}
              disabled={disabled || !canUndoMarkdownChange}
              aria-label="Undo"
              title="Undo"
            >
              <Undo2Icon />
            </Button>
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              onClick={redoMarkdownChange}
              disabled={disabled || !canRedoMarkdownChange}
              aria-label="Redo"
              title="Redo"
            >
              <Redo2Icon />
            </Button>
          </div>

          <Separator orientation="vertical" className="mx-1 my-auto h-[65%] self-center" />

          <div className="flex items-center gap-0.5">
            <SourceModeDropdownButton
              label="Heading"
              ariaLabel="Format text as heading"
              Icon={HeadingIcon}
            >
              {MARKDOWN_HEADING_OPTIONS.map((option) => {
                const Icon = HEADING_ICONS[option.level]

                return (
                  <DropdownMenuItem
                    key={option.level}
                    disabled={disabled}
                    aria-label={option.label}
                    title={option.label}
                    onClick={() => applyHeading(option.level)}
                  >
                    <Icon />
                    <span className="tiptap-button-text">{option.label}</span>
                  </DropdownMenuItem>
                )
              })}
            </SourceModeDropdownButton>
            <SourceModeDropdownButton label="List" ariaLabel="List options" Icon={ListIcon}>
              {MARKDOWN_LIST_OPTIONS.map((option) => {
                const Icon = LIST_ICONS[option.type]

                return (
                  <DropdownMenuItem
                    key={option.type}
                    disabled={disabled}
                    aria-label={option.label}
                    title={option.label}
                    onClick={() => applyList(option.type)}
                  >
                    <Icon />
                    <span className="tiptap-button-text">{option.label}</span>
                  </DropdownMenuItem>
                )
              })}
            </SourceModeDropdownButton>
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              onClick={applyBlockquote}
              disabled={disabled}
              aria-label="Blockquote"
              title="Blockquote"
            >
              <BlockquoteIcon />
            </Button>
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              onClick={insertCodeBlock}
              disabled={disabled}
              aria-label="Code Block"
              title="Code Block"
            >
              <CodeBlockIcon />
            </Button>
            <Button
              type="button"
              variant="ghost"
              size="icon-sm"
              onClick={insertDivider}
              disabled={disabled}
              aria-label="Insert divider"
              title="Divider"
            >
              <Minus />
            </Button>
          </div>

          <Separator orientation="vertical" className="mx-1 my-auto h-[65%] self-center" />

          <div className="flex items-center gap-0.5">
            {[
              {
                label: 'Bold',
                Icon: BoldIcon,
                onClick: applyBold
              },
              {
                label: 'Italic',
                Icon: ItalicIcon,
                onClick: applyItalic
              },
              {
                label: 'Strike',
                Icon: StrikeIcon,
                onClick: applyStrike
              },
              {
                label: 'Code',
                Icon: Code2Icon,
                onClick: applyCode
              },
              {
                label: 'Underline',
                Icon: UnderlineIcon,
                onClick: applyUnderline
              }
            ].map((mark) => (
              <Button
                key={mark.label}
                type="button"
                variant="ghost"
                size="icon-sm"
                onClick={mark.onClick}
                disabled={disabled}
                aria-label={mark.label}
                title={mark.label}
              >
                <mark.Icon />
              </Button>
            ))}
            <SourceColorHighlightPopover
              disabled={disabled}
              onHighlightColorSelect={(color) =>
                applyHighlight(getContentEditorHighlightColorName(color.value))
              }
              onRemoveHighlight={removeHighlight}
            />
            <LinkControlPopover
              canSet={!disabled}
              disabled={disabled}
              isActive={isMarkdownLinkActive}
              onOpenChange={handleMarkdownLinkPopoverOpenChange}
              removeLink={removeMarkdownLink}
              setLink={setMarkdownLink}
              setUrl={setMarkdownLinkUrl}
              url={markdownLinkUrl}
            />
          </div>

          <Separator orientation="vertical" className="mx-1 my-auto h-[65%] self-center" />

          <div className="flex items-center">
            <TableButton disabled={disabled} onInsertTable={insertTable} />
            <MathPopoverButton disabled={disabled} onInsertMath={insertMath} />
            <Button
              type="button"
              variant="ghost"
              size="sm"
              onClick={openMediaGalleryAtCursor}
              disabled={disabled}
              aria-label="Add media"
              title="Add media"
            >
              <ImagePlusIcon />
              <span className="tiptap-button-text">Media</span>
            </Button>
          </div>
        </div>

        {toolbarEnd ? <div className="flex shrink-0 items-center gap-0.5">{toolbarEnd}</div> : null}
      </EditorToolbar>

      <div className="flex min-h-0 flex-1 flex-col overflow-hidden">
        <CodeMirror
          ref={editorRef}
          value={value}
          onChange={handleEditorChange}
          onCreateEditor={handleCreateEditor}
          placeholder={placeholder}
          extensions={codeMirrorExtensions}
          theme={editorTheme}
          editable={!disabled}
          basicSetup={{
            lineNumbers: true,
            foldGutter: true,
            highlightActiveLine: false,
            highlightActiveLineGutter: false
          }}
          className={cn(
            'flex min-h-0 flex-1 flex-col overflow-hidden font-mono text-sm leading-6 font-normal [&_.cm-content]:!bg-transparent [&_.cm-editor]:!bg-input [&_.cm-gutters]:!bg-input [&_.cm-scroller]:!bg-input',
            {
              'cursor-not-allowed opacity-50': disabled
            }
          )}
        />
      </div>
    </div>
  )
}
