'use client';

import * as React from 'react';

import type { PlateEditor, PlateElementProps } from 'platejs/react';

import {
  CalendarIcon,
  ChevronRightIcon,
  Code2,
  Columns3Icon,
  Heading1Icon,
  Heading2Icon,
  Heading3Icon,
  Languages,
  LightbulbIcon,
  ListIcon,
  ListOrdered,
  PencilLine,
  PenToolIcon,
  PilcrowIcon,
  Quote,
  RadicalIcon,
  Sparkles,
  Square,
  Table,
  TableOfContentsIcon,
  Wand2,
} from 'lucide-react';
import { type TComboboxInputElement, KEYS } from 'platejs';
import { PlateElement } from 'platejs/react';

import {
  insertBlock,
  insertInlineElement,
} from '@/components/editor/transforms';
import {
  EMBED_PROVIDER_CONFIG,
  EMBED_PROVIDER_ORDER,
  useEmbedCard,
} from '@/components/editor/embed-card/embed-card-insert';
import { useOptionalAiAssistant } from '@/components/editor/ai-assistant/ai-assistant-context';
import { captureSelectionContext } from '@/components/editor/ai-assistant/selection';
import {
  ACTION_LABEL,
  type WriteAction,
} from '@/components/editor/ai-assistant/types';

import {
  InlineCombobox,
  InlineComboboxContent,
  InlineComboboxEmpty,
  InlineComboboxGroup,
  InlineComboboxGroupLabel,
  InlineComboboxInput,
  InlineComboboxItem,
} from './inline-combobox';

type Group = {
  group: string;
  items: {
    icon: React.ReactNode;
    value: string;
    onSelect: (editor: PlateEditor, value: string) => void;
    className?: string;
    focusEditor?: boolean;
    keywords?: string[];
    label?: string;
  }[];
};

const groups: Group[] = [
  {
    group: 'Basic blocks',
    items: [
      {
        icon: <PilcrowIcon />,
        keywords: ['paragraph'],
        label: 'Text',
        value: KEYS.p,
      },
      {
        icon: <Heading1Icon />,
        keywords: ['title', 'h1'],
        label: 'Heading 1',
        value: KEYS.h1,
      },
      {
        icon: <Heading2Icon />,
        keywords: ['subtitle', 'h2'],
        label: 'Heading 2',
        value: KEYS.h2,
      },
      {
        icon: <Heading3Icon />,
        keywords: ['subtitle', 'h3'],
        label: 'Heading 3',
        value: KEYS.h3,
      },
      {
        icon: <ListIcon />,
        keywords: ['unordered', 'ul', '-'],
        label: 'Bulleted list',
        value: KEYS.ul,
      },
      {
        icon: <ListOrdered />,
        keywords: ['ordered', 'ol', '1'],
        label: 'Numbered list',
        value: KEYS.ol,
      },
      {
        icon: <Square />,
        keywords: ['checklist', 'task', 'checkbox', '[]'],
        label: 'To-do list',
        value: KEYS.listTodo,
      },
      {
        icon: <ChevronRightIcon />,
        keywords: ['collapsible', 'expandable'],
        label: 'Toggle',
        value: KEYS.toggle,
      },
      {
        icon: <Code2 />,
        keywords: ['```'],
        label: 'Code Block',
        value: KEYS.codeBlock,
      },
      {
        icon: <Table />,
        label: 'Table',
        value: KEYS.table,
      },
      {
        icon: <Quote />,
        keywords: ['citation', 'blockquote', 'quote', '>'],
        label: 'Blockquote',
        value: KEYS.blockquote,
      },
      {
        description: 'Insert a highlighted block.',
        icon: <LightbulbIcon />,
        keywords: ['note'],
        label: 'Callout',
        value: KEYS.callout,
      },
    ].map((item) => ({
      ...item,
      onSelect: (editor, value) => {
        insertBlock(editor, value, { upsert: true });
      },
    })),
  },
  {
    group: 'Advanced blocks',
    items: [
      {
        icon: <TableOfContentsIcon />,
        keywords: ['toc'],
        label: 'Table of contents',
        value: KEYS.toc,
      },
      {
        icon: <Columns3Icon />,
        label: '3 columns',
        value: 'action_three_columns',
      },
      {
        focusEditor: false,
        icon: <RadicalIcon />,
        label: 'Equation',
        value: KEYS.equation,
      },
      {
        icon: <PenToolIcon />,
        keywords: ['excalidraw'],
        label: 'Excalidraw',
        value: KEYS.excalidraw,
      },
      {
        icon: <Code2 />,
        keywords: [
          'code-drawing',
          'diagram',
          'plantuml',
          'graphviz',
          'flowchart',
          'mermaid',
        ],
        label: 'Code Drawing',
        value: KEYS.codeDrawing,
      },
    ].map((item) => ({
      ...item,
      onSelect: (editor, value) => {
        insertBlock(editor, value, { upsert: true });
      },
    })),
  },
  {
    group: 'Inline',
    items: [
      {
        focusEditor: true,
        icon: <CalendarIcon />,
        keywords: ['time'],
        label: 'Date',
        value: KEYS.date,
      },
      {
        focusEditor: false,
        icon: <RadicalIcon />,
        label: 'Inline Equation',
        value: KEYS.inlineEquation,
      },
    ].map((item) => ({
      ...item,
      onSelect: (editor, value) => {
        insertInlineElement(editor, value);
      },
    })),
  },
];

const aiSlashItems: Array<{
  action: WriteAction;
  keywords: string[];
  icon: React.ReactNode;
}> = [
  { action: 'continue', keywords: ['ai', 'continue', 'xuxie', '续写'], icon: <PencilLine /> },
  { action: 'rewrite', keywords: ['ai', 'rewrite', 'gaixie', '改写'], icon: <Wand2 /> },
  { action: 'expand', keywords: ['ai', 'expand', 'kuozhan', '扩展'], icon: <Sparkles /> },
  { action: 'shorten', keywords: ['ai', 'shorten', 'jingjian', '精简'], icon: <Sparkles /> },
  { action: 'translate', keywords: ['ai', 'translate', 'fanyi', '翻译'], icon: <Languages /> },
  { action: 'tone', keywords: ['ai', 'tone', 'yuqi', '语气'], icon: <Wand2 /> },
];

const embedSlashKeywords: Record<string, string[]> = {
  github: ['github', 'repo', 'repository', 'git', '仓库'],
  tweet: ['tweet', 'twitter', 'x', 'post', '推文'],
  spotify: ['spotify', 'music', 'track', 'song', '音乐', '歌曲'],
};

export function SlashInputElement(
  props: PlateElementProps<TComboboxInputElement>
) {
  const { editor, element } = props;
  const assistant = useOptionalAiAssistant();
  const embed = useEmbedCard();

  return (
    <PlateElement {...props} as="span">
      <InlineCombobox element={element} trigger="/">
        <InlineComboboxInput />

        <InlineComboboxContent>
          <InlineComboboxEmpty>No results</InlineComboboxEmpty>

          {assistant ? (
            <InlineComboboxGroup>
              <InlineComboboxGroupLabel>AI 写作</InlineComboboxGroupLabel>
              {aiSlashItems.map((item) => (
                <InlineComboboxItem
                  key={`ai-${item.action}`}
                  value={`ai-${item.action}`}
                  label={`AI · ${ACTION_LABEL[item.action]}`}
                  focusEditor={false}
                  group="AI 写作"
                  keywords={item.keywords}
                  onClick={() => {
                    const context = captureSelectionContext(editor);
                    assistant.open({ context, initialAction: item.action });
                  }}
                >
                  <div className="mr-2 text-muted-foreground">{item.icon}</div>
                  AI · {ACTION_LABEL[item.action]}
                </InlineComboboxItem>
              ))}
            </InlineComboboxGroup>
          ) : null}

          <InlineComboboxGroup>
            <InlineComboboxGroupLabel>嵌入</InlineComboboxGroupLabel>
            {EMBED_PROVIDER_ORDER.map((provider) => {
              const config = EMBED_PROVIDER_CONFIG[provider];
              return (
                <InlineComboboxItem
                  key={`embed-${provider}`}
                  value={`embed-${provider}`}
                  label={config.label}
                  group="嵌入"
                  keywords={embedSlashKeywords[provider]}
                  onClick={() => embed.open(provider)}
                >
                  <div className="mr-2 text-muted-foreground">{config.icon}</div>
                  {config.label}
                </InlineComboboxItem>
              );
            })}
          </InlineComboboxGroup>

          {groups.map(({ group, items }) => (
            <InlineComboboxGroup key={group}>
              <InlineComboboxGroupLabel>{group}</InlineComboboxGroupLabel>

              {items.map(
                ({ focusEditor, icon, keywords, label, value, onSelect }) => (
                  <InlineComboboxItem
                    key={value}
                    value={value}
                    onClick={() => onSelect(editor, value)}
                    label={label}
                    focusEditor={focusEditor}
                    group={group}
                    keywords={keywords}
                  >
                    <div className="mr-2 text-muted-foreground">{icon}</div>
                    {label ?? value}
                  </InlineComboboxItem>
                )
              )}
            </InlineComboboxGroup>
          ))}
        </InlineComboboxContent>
      </InlineCombobox>

      {props.children}
    </PlateElement>
  );
}
