'use client';

import React, { useEffect, useLayoutEffect, useMemo, useRef, useState } from 'react';

const MENU_WIDTH = 375;
const MENU_MAX_HEIGHT = 360;
const VIEWPORT_MARGIN = 8;

const SHORTCUT_HINT = {
  paragraph: '',
  heading_1: '#',
  heading_2: '##',
  heading_3: '###',
  heading_4: '####',
  heading_5: '#####',
  heading_6: '######',
  bullet_item: '-',
  numbered_item: '1.',
  checklist: '[]',
  quote: '>',
  code: '```',
  divider: '---',
  image: '',
};
import { listBlocks } from './blockRegistry.js';

// Menu flottant des commandes. Affiché ancré à un élément (anchorRect).
// La navigation clavier (↑ ↓ Enter Esc) est gérée par le composant parent
// via la méthode imperative move()/select() — au MVP on garde simple :
// le composant parent passe `query` et `selectedIndex` ; on déclenche
// `onSelect` au clic ou via Enter (intercepté côté parent).

function fuzzyScore(label, keywords, query) {
  const q = query.toLowerCase().trim();
  if (!q) return 1;
  const haystack = [label, ...(keywords || [])].join(' ').toLowerCase();
  if (haystack.includes(q)) return 2;
  // Match partiel : tous les caractères dans l'ordre
  let i = 0;
  for (const c of haystack) {
    if (c === q[i]) i++;
    if (i === q.length) return 1;
  }
  return 0;
}

export default function SlashMenu({
  query = '',
  anchorRect,
  enabledBlocks,
  selectedIndex,
  onSelect,
  onHoverIndex,
}) {
  const allowed = useMemo(() => {
    const all = listBlocks();
    return enabledBlocks ? all.filter(b => enabledBlocks.includes(b.type)) : all;
  }, [enabledBlocks]);

  const items = useMemo(() => {
    return allowed
      .map(def => ({ def, score: fuzzyScore(def.label, def.keywords, query) }))
      .filter(x => x.score > 0)
      .sort((a, b) => b.score - a.score)
      .map(x => x.def);
  }, [allowed, query]);

  const listRef = useRef(null);
  const [position, setPosition] = useState({ top: 0, bottom: null, left: 0, maxHeight: MENU_MAX_HEIGHT });

  // Scroll l'élément sélectionné dans la vue (interne au menu uniquement)
  useEffect(() => {
    const el = listRef.current?.querySelector(`[data-slash-index="${selectedIndex}"]`);
    if (el) el.scrollIntoView({ block: 'nearest' });
  }, [selectedIndex]);

  // Positionnement adaptatif : flip au-dessus si pas assez de place en bas,
  // clamp horizontalement, et limite la hauteur à l'espace disponible.
  // Quand on est en mode « au-dessus », on ancre via `bottom` plutôt que
  // `top` — sinon, quand le contenu rétrécit (filtrage par query), le bas
  // de la boîte décolle du champ et flotte en l'air.
  useLayoutEffect(() => {
    if (!anchorRect || typeof window === 'undefined') return;
    const vh = window.innerHeight;
    const vw = window.innerWidth;
    const spaceBelow = vh - anchorRect.bottom - VIEWPORT_MARGIN;
    const spaceAbove = anchorRect.top - VIEWPORT_MARGIN;

    let top = null;
    let bottom = null;
    let maxHeight;
    if (spaceBelow >= Math.min(MENU_MAX_HEIGHT, 200) || spaceBelow >= spaceAbove) {
      top = anchorRect.bottom + 6;
      maxHeight = Math.max(120, Math.min(MENU_MAX_HEIGHT, spaceBelow - 6));
    } else {
      bottom = vh - anchorRect.top + 6;
      maxHeight = Math.max(120, Math.min(MENU_MAX_HEIGHT, spaceAbove - 6));
    }

    let left = anchorRect.left;
    if (left + MENU_WIDTH + VIEWPORT_MARGIN > vw) {
      left = Math.max(VIEWPORT_MARGIN, vw - MENU_WIDTH - VIEWPORT_MARGIN);
    }
    if (left < VIEWPORT_MARGIN) left = VIEWPORT_MARGIN;

    setPosition({ top, bottom, left, maxHeight });
  }, [anchorRect]);

  if (!anchorRect) return null;

  const { top, bottom, left, maxHeight } = position;
  const positionStyle = bottom != null
    ? { bottom, left, width: MENU_WIDTH, maxHeight }
    : { top, left, width: MENU_WIDTH, maxHeight };

  if (items.length === 0) {
    return (
      <div
        className="fixed z-50 rounded-lg border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 shadow-md px-3 py-2 text-xs text-neutral-500"
        style={positionStyle}
      >
        Aucune commande pour « {query} »
      </div>
    );
  }

  return (
    <div
      ref={listRef}
      data-slash-menu
      className="fixed z-50 overflow-y-auto rounded-lg border border-neutral-200 dark:border-neutral-700 bg-white dark:bg-neutral-900 shadow-md py-1"
      style={positionStyle}
      onMouseDown={(e) => e.preventDefault()} // ne pas voler le focus
    >
      <div className="px-3 pt-1.5 pb-1 text-[10px] font-medium uppercase tracking-wider text-neutral-400 dark:text-neutral-500">
        Blocs de base
      </div>
      {items.map((def, i) => {
        const active = i === selectedIndex;
        const hint = SHORTCUT_HINT[def.type];
        return (
          <button
            key={def.type}
            type="button"
            data-slash-index={i}
            onMouseEnter={() => onHoverIndex?.(i)}
            onClick={() => onSelect?.(def.type)}
            className={`w-full flex items-center gap-3 px-2 py-1.5 text-left transition-colors ${active ? 'bg-neutral-100 dark:bg-neutral-800' : ''}`}
          >
            <span className="w-8 h-8 flex items-center justify-center rounded-md border border-neutral-200 dark:border-neutral-700 text-xs font-medium text-neutral-700 dark:text-neutral-300 flex-shrink-0">
              {def.icon}
            </span>
            <span className="flex-1 min-w-0 truncate text-sm text-neutral-900 dark:text-white">
              {def.label}
            </span>
            {hint && (
              <span className="text-xs font-mono text-neutral-400 dark:text-neutral-500 flex-shrink-0">
                {hint}
              </span>
            )}
          </button>
        );
      })}
    </div>
  );
}

// Helper exposé pour le parent : ordre des items pour navigation clavier.
export function getSlashItems(query, enabledBlocks) {
  const all = listBlocks();
  const allowed = enabledBlocks ? all.filter(b => enabledBlocks.includes(b.type)) : all;
  return allowed
    .map(def => ({ def, score: fuzzyScore(def.label, def.keywords, query) }))
    .filter(x => x.score > 0)
    .sort((a, b) => b.score - a.score)
    .map(x => x.def);
}
