// CommandPalette.jsx — Global ⌘K palette for Vestora broker dashboard
// Categories: Actions (fixed), Clients (window.vestora.brokerClients),
//             Listings (window.LISTINGS), Glossary (GLOSSARY)

const { useState: useCPState, useEffect: useCPEffect, useRef: useCPRef, useMemo: useCPMemo, useCallback: useCPCb } = React;

/* ── Helpers ────────────────────────────────────────────────── */

// Substring match insensible à la casse — retourne true + indices des matches
function substringMatch(text, query) {
  if (!query) return { match: true, ranges: [] };
  const tl = (text || '').toLowerCase();
  const ql = query.toLowerCase().trim();
  if (!ql) return { match: true, ranges: [] };
  const idx = tl.indexOf(ql);
  if (idx === -1) return { match: false, ranges: [] };
  return { match: true, ranges: [[idx, idx + ql.length]] };
}

// Highlight : insère <mark> autour des plages matchées
function HighlightText({ text, query }) {
  if (!query || !text) return <span>{text}</span>;
  const ql = query.toLowerCase().trim();
  const idx = text.toLowerCase().indexOf(ql);
  if (idx === -1) return <span>{text}</span>;
  return (
    <span>
      {text.slice(0, idx)}
      <span className="cp-match">{text.slice(idx, idx + ql.length)}</span>
      {text.slice(idx + ql.length)}
    </span>
  );
}

/* ── Static Actions ─────────────────────────────────────────── */
function buildActions(isMac) {
  return [
    { id: 'act-mandats',    label: 'Nouveau mandat',           sub: 'Dashboard courtier → Mandats',    icon: '📋', action: () => window.navigateTo('#/courtier?tab=mandats') },
    { id: 'act-clients',    label: 'Nouveau client',           sub: 'Dashboard courtier → Clients',    icon: '👤', action: () => window.navigateTo('#/courtier?tab=clients') },
    { id: 'act-cma',        label: 'Exporter CMA',             sub: 'Analyse comparative de marché',   icon: '📊', action: () => window.navigateTo('#/courtier/cma') },
    { id: 'act-profil',     label: 'Voir mon profil',          sub: 'Profil courtier brandé',          icon: '🪪', action: () => window.navigateTo('#/courtier/profil') },
    { id: 'act-wealth',     label: 'Wealth Simulator',         sub: 'Simulateur de richesse immobilière', icon: '💰', action: () => window.navigateTo('#/courtier') }, // ouvrira dans app
    { id: 'act-theme',      label: 'Basculer thème dark / magazine', sub: 'Changer le thème visuel',   icon: '🎨', action: () => {
        const el = document.documentElement;
        const cur = el.dataset.theme || 'dark';
        const next = cur === 'dark' ? 'magazine' : 'dark';
        el.dataset.theme = next;
        try { localStorage.setItem('vestora_theme', next); } catch (e) {}
      }
    },
    { id: 'act-logout',     label: 'Se déconnecter',           sub: 'Fermer la session',               icon: '🔓', action: () => {
        const auth = window.vestora && window.vestora.auth;
        if (auth && typeof auth.signOut === 'function') {
          auth.signOut().catch(() => {});
        } else {
          window.navigateTo('#/');
        }
      }
    },
  ];
}

/* ── Listings index ─────────────────────────────────────────── */
function getListings() {
  return window.LISTINGS || (window.APP_DATA && window.APP_DATA.listings) || [];
}

function searchListings(query, max) {
  if (!query || query.length < 2) return [];
  const all = getListings();
  const results = [];
  for (let i = 0; i < all.length && results.length < max; i++) {
    const l = all[i];
    const haystack = [l.address || '', l.city || '', l.mls || '', String(l.id || '')].join(' ');
    if (substringMatch(haystack, query).match) {
      results.push(l);
    }
  }
  return results;
}

/* ── Clients index ──────────────────────────────────────────── */
function getBrokerClients() {
  const bc = window.vestora && window.vestora.brokerClients;
  if (!bc) return [];
  if (Array.isArray(bc)) return bc;            // tolère un tableau direct
  if (Array.isArray(bc.list)) return bc.list;
  return [];
}

const STAGE_LABELS = {
  lead: 'Nouveau lead',
  qualified: 'Qualifié',
  visiting: 'En visite',
  offer: 'Offre déposée',
  under_contract: 'Sous contrat',
  closed: 'Closé',
  lost: 'Perdu',
};

function searchClients(query, max) {
  if (!query || query.length < 2) return [];
  const all = getBrokerClients();
  if (all.length === 0) return [];
  const results = [];
  for (let i = 0; i < all.length && results.length < max; i++) {
    const c = all[i];
    const haystack = [
      c.name || '',
      c.email || '',
      c.phone || '',
      c.stage || '',
      STAGE_LABELS[c.stage] || '',
      (c.cities || []).join(' '),
    ].join(' ');
    if (substringMatch(haystack, query).match) {
      results.push(c);
    }
  }
  return results;
}

function openBrokerClient(id) {
  const bc = window.vestora && window.vestora.brokerClients;
  if (bc && typeof bc.openById === 'function') {
    // Bascule vers l'onglet Clients si besoin, puis ouvre la fiche.
    try {
      const onCourtier = (location.hash || '').startsWith('#/courtier');
      if (!onCourtier) {
        window.navigateTo('#/courtier?tab=clients');
        // Laisse le temps au tab de monter avant d'ouvrir la fiche.
        setTimeout(() => {
          try {
            const bc2 = window.vestora && window.vestora.brokerClients;
            if (bc2 && typeof bc2.openById === 'function') bc2.openById(id);
          } catch (_e) {}
        }, 250);
        return;
      }
    } catch (_e) {}
    bc.openById(id);
    return;
  }
  // Fallback : route URL (le tab Clients peut lire ?client= au mount)
  window.navigateTo('#/courtier?tab=clients&client=' + encodeURIComponent(id));
}

/* ── Glossary index ─────────────────────────────────────────── */
function getGlossaryEntries() {
  // GLOSSARY est défini dans glossary.js — exposé via window ou accessible directement
  if (typeof GLOSSARY !== 'undefined') return Object.values(GLOSSARY);
  if (window.GLOSSARY) return Object.values(window.GLOSSARY);
  if (window.vestora && window.vestora.glossary) return Object.values(window.vestora.glossary);
  return [];
}

function searchGlossary(query, max) {
  if (!query || query.length < 2) return [];
  const entries = getGlossaryEntries();
  const results = [];
  for (let i = 0; i < entries.length && results.length < max; i++) {
    const e = entries[i];
    const haystack = (e.label || '') + ' ' + (e.short_def || '');
    if (substringMatch(haystack, query).match) {
      results.push(e);
    }
  }
  return results;
}

/* ── GlossaryMiniModal ──────────────────────────────────────── */
function GlossaryMiniModal({ entry, onClose }) {
  useCPEffect(() => {
    const handler = (e) => { if (e.key === 'Escape') onClose(); };
    document.addEventListener('keydown', handler);
    return () => document.removeEventListener('keydown', handler);
  }, [onClose]);

  return (
    <div
      className="cp-backdrop"
      style={{ zIndex: 9100 }}
      onClick={onClose}
      role="dialog"
      aria-modal="true"
      aria-label={entry.label}
    >
      <div
        className="cp-modal"
        style={{ maxWidth: 480, padding: 'var(--sp-6)' }}
        onClick={e => e.stopPropagation()}
      >
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: 'var(--sp-3)' }}>
          <span style={{ fontFamily: 'var(--sans)', fontSize: 'var(--fs-lg)', fontWeight: 600, color: 'var(--ink-1)' }}>
            {entry.label}
          </span>
          <button className="cp-clear-btn" onClick={onClose} aria-label="Fermer">✕</button>
        </div>
        <p style={{ fontFamily: 'var(--sans)', fontSize: 'var(--fs-base)', color: 'var(--ink-2)', lineHeight: 'var(--lh-normal)', margin: '0 0 var(--sp-3)' }}>
          {entry.short_def}
        </p>
        {entry.example && (
          <p style={{ fontFamily: 'var(--mono)', fontSize: 'var(--fs-small)', color: 'var(--ink-3)', margin: 0, borderLeft: '2px solid var(--line)', paddingLeft: 'var(--sp-3)', lineHeight: 'var(--lh-normal)' }}>
            {entry.example}
          </p>
        )}
        {entry.see_also && entry.see_also.length > 0 && (
          <p style={{ fontFamily: 'var(--sans)', fontSize: 'var(--fs-small)', color: 'var(--ink-4)', marginTop: 'var(--sp-3)', marginBottom: 0 }}>
            Voir aussi : {entry.see_also.join(', ')}
          </p>
        )}
      </div>
    </div>
  );
}

/* ── CommandPalette ─────────────────────────────────────────── */
function CommandPalette({ open, onClose, lang, onSelectListing }) {
  const [query, setQueryRaw] = useCPState('');
  const [selectedIdx, setSelectedIdx] = useCPState(0);
  const [glossaryEntry, setGlossaryEntry] = useCPState(null);
  const inputRef = useCPRef(null);
  const listRef = useCPRef(null);
  const prevFocusRef = useCPRef(null);
  const isMac = typeof navigator !== 'undefined' && /Mac|iPhone|iPad/i.test(navigator.platform || navigator.userAgent);

  const setQuery = (v) => { setQueryRaw(v); setSelectedIdx(0); };

  // Focus management
  useCPEffect(() => {
    if (open) {
      prevFocusRef.current = document.activeElement;
      requestAnimationFrame(() => inputRef.current && inputRef.current.focus());
    } else {
      if (prevFocusRef.current && typeof prevFocusRef.current.focus === 'function') {
        prevFocusRef.current.focus();
      }
    }
  }, [open]);

  // Restore theme from localStorage on mount
  useCPEffect(() => {
    try {
      const saved = localStorage.getItem('vestora_theme');
      if (saved && document.documentElement.dataset.theme !== saved) {
        document.documentElement.dataset.theme = saved;
      }
    } catch (e) {}
  }, []);

  // Build result groups
  const actions = useCPMemo(() => buildActions(isMac), [isMac]);

  const filteredActions = useCPMemo(() => {
    if (!query.trim()) return actions.slice(0, 5);
    return actions.filter(a => substringMatch(a.label + ' ' + (a.sub || ''), query).match).slice(0, 5);
  }, [query, actions]);

  const filteredClients = useCPMemo(() => {
    if (!query.trim() || query.trim().length < 2) return [];
    return searchClients(query, 5);
  }, [query]);

  const filteredListings = useCPMemo(() => {
    if (!query.trim() || query.trim().length < 2) return [];
    return searchListings(query, 5);
  }, [query]);

  const filteredGlossary = useCPMemo(() => {
    if (!query.trim() || query.trim().length < 2) return [];
    return searchGlossary(query, 3);
  }, [query]);

  // Flatten all items for keyboard nav (ordre = ordre d'affichage)
  const allItems = useCPMemo(() => {
    const items = [];
    filteredActions.forEach(a => items.push({ type: 'action', data: a }));
    filteredClients.forEach(c => items.push({ type: 'client', data: c }));
    filteredListings.forEach(l => items.push({ type: 'listing', data: l }));
    filteredGlossary.forEach(g => items.push({ type: 'glossary', data: g }));
    return items;
  }, [filteredActions, filteredClients, filteredListings, filteredGlossary]);

  const totalItems = allItems.length;

  // Scroll selected item into view
  useCPEffect(() => {
    if (!listRef.current) return;
    const el = listRef.current.querySelector('.cp-item--selected');
    if (el) el.scrollIntoView({ block: 'nearest' });
  }, [selectedIdx]);

  const handleKeyDown = useCPCb((e) => {
    if (!open) return;
    switch (e.key) {
      case 'Escape':
        e.preventDefault();
        onClose();
        break;
      case 'ArrowDown':
        e.preventDefault();
        setSelectedIdx(i => Math.min(i + 1, totalItems - 1));
        break;
      case 'ArrowUp':
        e.preventDefault();
        setSelectedIdx(i => Math.max(i - 1, 0));
        break;
      case 'Enter':
        e.preventDefault();
        if (allItems[selectedIdx]) activateItem(allItems[selectedIdx]);
        break;
      default:
        break;
    }
  }, [open, allItems, selectedIdx, totalItems]);

  useCPEffect(() => {
    document.addEventListener('keydown', handleKeyDown);
    return () => document.removeEventListener('keydown', handleKeyDown);
  }, [handleKeyDown]);

  const activateItem = (item) => {
    if (item.type === 'action') {
      onClose();
      item.data.action();
    } else if (item.type === 'client') {
      onClose();
      openBrokerClient(item.data.id);
    } else if (item.type === 'listing') {
      onClose();
      if (typeof onSelectListing === 'function') {
        onSelectListing(item.data.id);
      } else {
        // Fallback: navigate to explorer with listing selected
        window.navigateTo('#/?listing=' + encodeURIComponent(item.data.id));
      }
    } else if (item.type === 'glossary') {
      setGlossaryEntry(item.data);
    }
  };

  if (!open) return null;

  // Count flat index offset per group (ordre = ordre d'affichage)
  let actionOffset = 0;
  let clientOffset = filteredActions.length;
  let listingOffset = filteredActions.length + filteredClients.length;
  let glossaryOffset = filteredActions.length + filteredClients.length + filteredListings.length;

  return (
    <>
      <div
        className="cp-backdrop"
        onClick={onClose}
        role="dialog"
        aria-modal="true"
        aria-label="Palette de commandes"
      >
        <div
          className="cp-modal"
          onClick={e => e.stopPropagation()}
        >
          {/* Search input */}
          <div className="cp-search-row">
            <svg className="cp-search-icon" width="16" height="16" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.8">
              <circle cx="6.5" cy="6.5" r="4.5"/>
              <line x1="10.5" y1="10.5" x2="14" y2="14"/>
            </svg>
            <input
              ref={inputRef}
              className="cp-search-input"
              type="text"
              placeholder="Rechercher une action, client, listing, terme…"
              value={query}
              onChange={e => setQuery(e.target.value)}
              aria-label="Recherche"
              autoComplete="off"
              spellCheck={false}
            />
            {query && (
              <button
                className="cp-clear-btn"
                onClick={() => setQuery('')}
                aria-label="Effacer"
              >
                <svg width="14" height="14" viewBox="0 0 14 14" stroke="currentColor" strokeWidth="1.8" fill="none">
                  <line x1="2" y1="2" x2="12" y2="12"/>
                  <line x1="12" y1="2" x2="2" y2="12"/>
                </svg>
              </button>
            )}
          </div>

          {/* Results */}
          <div className="cp-results" ref={listRef} role="listbox" aria-label="Résultats">
            {allItems.length === 0 && query.length >= 2 && (
              <div className="cp-empty">Aucun résultat pour « {query} »</div>
            )}

            {/* Actions */}
            {filteredActions.length > 0 && (
              <>
                <div className="cp-category-label">Actions</div>
                {filteredActions.map((item, i) => {
                  const flatIdx = actionOffset + i;
                  return (
                    <div
                      key={item.id}
                      className={'cp-item' + (selectedIdx === flatIdx ? ' cp-item--selected' : '')}
                      role="option"
                      aria-selected={selectedIdx === flatIdx}
                      onClick={() => activateItem({ type: 'action', data: item })}
                      onMouseEnter={() => setSelectedIdx(flatIdx)}
                    >
                      <div className="cp-item-icon">{item.icon}</div>
                      <div className="cp-item-body">
                        <div className="cp-item-title">
                          <HighlightText text={item.label} query={query} />
                        </div>
                        {item.sub && <div className="cp-item-sub">{item.sub}</div>}
                      </div>
                    </div>
                  );
                })}
              </>
            )}

            {/* Clients */}
            {filteredClients.length > 0 && (
              <>
                <div className="cp-category-label">Clients</div>
                {filteredClients.map((client, i) => {
                  const flatIdx = clientOffset + i;
                  const title = client.name || (client.email || ('Client #' + client.id));
                  const subParts = [];
                  if (STAGE_LABELS[client.stage]) subParts.push(STAGE_LABELS[client.stage]);
                  if (client.email) subParts.push(client.email);
                  else if (client.phone) subParts.push(client.phone);
                  if (client.cities && client.cities.length > 0) {
                    subParts.push(client.cities.slice(0, 2).join(', ') + (client.cities.length > 2 ? '…' : ''));
                  }
                  const sub = subParts.join(' · ');
                  return (
                    <div
                      key={'cli-' + client.id}
                      className={'cp-item' + (selectedIdx === flatIdx ? ' cp-item--selected' : '')}
                      role="option"
                      aria-selected={selectedIdx === flatIdx}
                      onClick={() => activateItem({ type: 'client', data: client })}
                      onMouseEnter={() => setSelectedIdx(flatIdx)}
                    >
                      <div className="cp-item-icon">
                        <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6">
                          <circle cx="8" cy="5.5" r="2.5"/>
                          <path d="M3 14c0-2.8 2.2-5 5-5s5 2.2 5 5"/>
                        </svg>
                      </div>
                      <div className="cp-item-body">
                        <div className="cp-item-title">
                          <HighlightText text={title} query={query} />
                        </div>
                        {sub && <div className="cp-item-sub">{sub}</div>}
                      </div>
                    </div>
                  );
                })}
              </>
            )}

            {/* Listings */}
            {filteredListings.length > 0 && (
              <>
                <div className="cp-category-label">Listings</div>
                {filteredListings.map((listing, i) => {
                  const flatIdx = listingOffset + i;
                  const title = listing.address || listing.city || String(listing.id);
                  const sub = [listing.city, listing.mls ? `MLS ${listing.mls}` : null].filter(Boolean).join(' · ');
                  return (
                    <div
                      key={listing.id}
                      className={'cp-item' + (selectedIdx === flatIdx ? ' cp-item--selected' : '')}
                      role="option"
                      aria-selected={selectedIdx === flatIdx}
                      onClick={() => activateItem({ type: 'listing', data: listing })}
                      onMouseEnter={() => setSelectedIdx(flatIdx)}
                    >
                      <div className="cp-item-icon">
                        <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6">
                          <path d="M8 2L2 7v7h4v-4h4v4h4V7L8 2z"/>
                        </svg>
                      </div>
                      <div className="cp-item-body">
                        <div className="cp-item-title">
                          <HighlightText text={title} query={query} />
                        </div>
                        {sub && <div className="cp-item-sub">{sub}</div>}
                      </div>
                      {listing.score != null && (
                        <span style={{
                          fontFamily: 'var(--mono)',
                          fontSize: 'var(--fs-caption)',
                          color: listing.score >= 70 ? 'var(--pos)' : listing.score >= 50 ? 'var(--warn)' : 'var(--ink-3)',
                          fontWeight: 600,
                          flexShrink: 0,
                        }}>
                          {Math.round(listing.score)}
                        </span>
                      )}
                    </div>
                  );
                })}
              </>
            )}

            {/* Glossary */}
            {filteredGlossary.length > 0 && (
              <>
                <div className="cp-category-label">Glossaire</div>
                {filteredGlossary.map((entry, i) => {
                  const flatIdx = glossaryOffset + i;
                  const sub = (entry.short_def || '').slice(0, 80) + ((entry.short_def || '').length > 80 ? '…' : '');
                  return (
                    <div
                      key={entry.id}
                      className={'cp-item' + (selectedIdx === flatIdx ? ' cp-item--selected' : '')}
                      role="option"
                      aria-selected={selectedIdx === flatIdx}
                      onClick={() => activateItem({ type: 'glossary', data: entry })}
                      onMouseEnter={() => setSelectedIdx(flatIdx)}
                    >
                      <div className="cp-item-icon">
                        <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.6">
                          <rect x="2" y="2" width="12" height="12" rx="2"/>
                          <path d="M5 6h6M5 8.5h4M5 11h5"/>
                        </svg>
                      </div>
                      <div className="cp-item-body">
                        <div className="cp-item-title">
                          <HighlightText text={entry.label} query={query} />
                        </div>
                        {sub && <div className="cp-item-sub">{sub}</div>}
                      </div>
                    </div>
                  );
                })}
              </>
            )}

            {/* Default: no query yet */}
            {allItems.length === 0 && !query.trim() && (
              <div className="cp-empty" style={{ paddingTop: 'var(--sp-4)' }}>
                Tapez pour chercher une action, un client, un listing ou un terme…
              </div>
            )}
          </div>

          {/* Footer keyboard hints */}
          <div className="cp-footer">
            <span className="cp-hint"><span className="cp-key">↑</span><span className="cp-key">↓</span> naviguer</span>
            <span className="cp-hint"><span className="cp-key">⏎</span> ouvrir</span>
            <span className="cp-hint"><span className="cp-key">Esc</span> fermer</span>
          </div>
        </div>
      </div>

      {/* Glossary mini-modal */}
      {glossaryEntry && (
        <GlossaryMiniModal
          entry={glossaryEntry}
          onClose={() => setGlossaryEntry(null)}
        />
      )}
    </>
  );
}

// Expose en global
window.CommandPalette = CommandPalette;
