import Mention from '@tiptap/extension-mention';
import type { AnyExtension } from '@tiptap/core';
import type { SuggestionProps, SuggestionKeyDownProps } from '@tiptap/suggestion';
import { ReactRenderer } from '@tiptap/react';

import { MentionList } from './MentionList.js';

export interface MentionUser {
  id: string;
  label: string;
}

/** Resolver that returns matching people for a query (sync or async). */
export type UserSearchFn = (query: string) => MentionUser[] | Promise<MentionUser[]>;

/**
 * Pure, case-insensitive in-memory matcher — handy as a default `UserSearchFn`
 * and directly unit-testable. Caps results at `limit`.
 */
export function filterUsers(query: string, users: MentionUser[], limit = 5): MentionUser[] {
  const q = query.trim().toLowerCase();
  const matches = q ? users.filter(u => u.label.toLowerCase().includes(q)) : users;
  return matches.slice(0, limit);
}

/**
 * Build a configured `@`-mention extension backed by an async people search.
 * Renders a keyboard-navigable popup at the caret.
 */
export function createMention(search: UserSearchFn): AnyExtension {
  return Mention.configure({
    HTMLAttributes: { class: 'bl-mention' },
    suggestion: {
      char: '@',
      items: async ({ query }) => await search(query),
      render: () => {
        let component: ReactRenderer<{ onKeyDown: (p: SuggestionKeyDownProps) => boolean }> | null =
          null;
        let popup: HTMLDivElement | null = null;

        const position = (props: SuggestionProps<MentionUser>) => {
          if (!popup) return;
          const rect = props.clientRect?.();
          if (!rect) return;
          popup.style.left = `${rect.left}px`;
          popup.style.top = `${rect.bottom + 4}px`;
        };

        return {
          onStart: (props: SuggestionProps<MentionUser>) => {
            component = new ReactRenderer(MentionList, { props, editor: props.editor });
            popup = document.createElement('div');
            popup.setAttribute('data-mention-menu', 'true');
            popup.style.position = 'absolute';
            popup.style.zIndex = '50';
            popup.appendChild(component.element);
            document.body.appendChild(popup);
            position(props);
          },
          onUpdate: (props: SuggestionProps<MentionUser>) => {
            component?.updateProps(props);
            position(props);
          },
          onKeyDown: (props: SuggestionKeyDownProps) => {
            if (props.event.key === 'Escape') {
              popup?.remove();
              return true;
            }
            return component?.ref?.onKeyDown(props) ?? false;
          },
          onExit: () => {
            popup?.remove();
            popup = null;
            component?.destroy();
            component = null;
          },
        };
      },
    },
  });
}
