/* query-inspector.jsx — type any prompt, fire it at every wired model in parallel,
 * watch six columns of REAL responses land. Highlights brand mentions and known
 * competitors inline.
 *
 * Data flow:
 *   user types → click Ask → fan-out callModel() per wired provider →
 *   each model resolves independently → its card updates with text + parsed result
 *
 * History persisted to localStorage under `aiso:queries:v1`.
 */

const { useState, useEffect, useRef, useMemo } = React;

const QUERY_HISTORY_KEY = 'aiso:queries:v1';

function loadQueryHistory() {
  try { return JSON.parse(localStorage.getItem(QUERY_HISTORY_KEY) || '[]'); }
  catch { return []; }
}
function pushQueryHistory(entry) {
  try {
    const arr = loadQueryHistory();
    const next = [entry, ...arr].slice(0, 24);
    localStorage.setItem(QUERY_HISTORY_KEY, JSON.stringify(next));
  } catch {}
}

/* Highlight brand + competitor names in response text */
function highlightText(text, brand, competitors) {
  if (!text) return null;
  const tokens = [
    ...(brand ? [{ pattern: brand, kind: 'brand' }] : []),
    ...(competitors || []).slice(0, 10).map(c => ({ pattern: c.name || c, kind: 'comp' })),
  ].filter(t => t.pattern && t.pattern.length >= 3);

  if (tokens.length === 0) return text;

  // Build a combined regex with capturing
  const escaped = tokens.map(t => t.pattern.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
  const re = new RegExp(`(${escaped.join('|')})`, 'gi');
  const parts = text.split(re);
  return parts.map((part, i) => {
    if (!part) return null;
    const matched = tokens.find(t => t.pattern.toLowerCase() === part.toLowerCase());
    if (matched) {
      return <span key={i} className={`qi-mark qi-mark-${matched.kind}`}>{part}</span>;
    }
    return <React.Fragment key={i}>{part}</React.Fragment>;
  });
}

/* Pull the actual recommended brand/product names out of a model's answer.
 * Heuristic (no extra LLM call): bold spans + numbered/headed list items, minus
 * the obvious labels ("Best for:", "Use case", …). Returns [{name, rank}] by order. */
const _BRAND_STOP = /^(best for|use cases?|scale|integration|budget|why|pros|cons|overview|pricing|features?|what to consider|top recommendations?|recommendations?|note|summary|conclusion|key features?|bottom line|considerations?|important|examples?|tl;?dr|what to look for|my recommendation|in short|others?|other options?|free|paid|enterprise|startup|small business|caveats?|disclaimer|honorable mentions?|the verdict|takeaway|how it works|use it (if|when))$/i;
function extractBrands(text) {
  if (!text) return [];
  const cands = [];
  let m;
  const reBold = /\*\*([^*\n]{2,40})\*\*/g;
  while ((m = reBold.exec(text))) {
    if (text[m.index + m[0].length] === ':') continue; // "**Label:** …" is a label, not a brand
    cands.push({ raw: m[1], pos: m.index });
  }
  const reNum = /^\s*#{0,4}\s*(\d+)[.)]\s+\*{0,2}([A-Z][^\n:–—]{1,40})/gm;
  while ((m = reNum.exec(text))) cands.push({ raw: m[2], pos: m.index });
  const out = new Map();
  for (const c of cands) {
    let name = c.raw.replace(/\*+/g, '').replace(/^\d+[.)]\s*/, '').replace(/[:–—].*$/, '').trim().replace(/[.,;]+$/, '').trim();
    if (name.length < 2 || name.length > 34) continue;
    if (!/^[A-Z0-9]/.test(name) || !/[A-Za-z]/.test(name)) continue; // brands start uppercase
    if (name.split(/\s+/).length > 5) continue;
    if (_BRAND_STOP.test(name)) continue;
    const key = name.toLowerCase();
    if (!out.has(key)) out.set(key, { name, pos: c.pos });
  }
  return [...out.values()].sort((a, b) => a.pos - b.pos).map((b, i) => ({ name: b.name, rank: i + 1 }));
}

function suggestedPromptsFor(brand) {
  if (!brand) return [];
  const ind = brand.industry || 'business';
  const loc = brand.location;
  const local = loc && loc !== 'Online' && loc !== 'Global' && loc !== 'unknown';
  return [
    local ? `Best ${ind} in ${loc}?` : `Best ${ind} right now?`,
    `Have you heard of ${brand.name}?`,
    `Recommend a great ${ind}.`,
    `Compare top ${ind} providers.`,
    local ? `Where should I go for ${ind} in ${loc}?` : `Where do experts recommend for ${ind}?`,
  ].filter(Boolean);
}

function QueryInspector({ brand, profile, onSettings }) {
  const [prompt, setPrompt] = useState('');
  const [running, setRunning] = useState(false);
  const [results, setResults] = useState({}); // { [providerId]: { status, text, error, parsed, elapsed } }
  const [history, setHistory] = useState(() => loadQueryHistory());
  const abortRef = useRef(null);

  const wired = (window.useWiredProviders ? window.useWiredProviders(profile) : (window.PROVIDERS || []).filter(p => profile?.keys?.[p.id]));
  const managedMode = window.aisoEnabled && window.aisoEnabled();
  const suggestions = useMemo(() => suggestedPromptsFor(brand), [brand?.domain, brand?.industry, brand?.location]);

  const competitors = brand?.competitors || [];

  async function ask(text) {
    const q = (text || prompt).trim();
    if (!q || running) return;
    if (wired.length === 0) {
      window.aisoToast('No models available right now — try again in a moment.', 'info');
      return;
    }
    abortRef.current?.abort();
    const ctrl = new AbortController();
    abortRef.current = ctrl;

    setRunning(true);
    const initial = {};
    wired.forEach(p => { initial[p.id] = { status: 'running', text: '', elapsed: 0 }; });
    setResults(initial);

    const allBrand = brand?.name || '';
    const allDomain = brand?.domain || '';

    const promises = wired.map(async (provider) => {
      const t0 = performance.now();
      try {
        // In managed mode, callModel ignores the BYO key arg. In BYO mode, pass it.
        const userKey = profile?.keys?.[provider.id];
        const r = await window.callModel(provider.id, userKey, q, { maxTokens: 500 });
        if (ctrl.signal.aborted) return;
        const parsed = window.parseMention(r.text, allBrand, allDomain);
        const brands = extractBrands(r.text);
        const elapsed = Math.round(performance.now() - t0);
        setResults(prev => ({ ...prev, [provider.id]: { status: 'done', text: r.text, parsed, brands, elapsed, model: r.model } }));
      } catch (e) {
        if (ctrl.signal.aborted) return;
        const elapsed = Math.round(performance.now() - t0);
        setResults(prev => ({ ...prev, [provider.id]: { status: 'error', error: String(e.message || e).slice(0, 200), elapsed } }));
      }
    });

    await Promise.allSettled(promises);
    if (ctrl.signal.aborted) return;

    setRunning(false);
    const entry = {
      id: Date.now(),
      at: Date.now(),
      prompt: q,
      brand: allBrand,
      domain: allDomain,
    };
    pushQueryHistory(entry);
    setHistory(loadQueryHistory());
  }

  const wiredCount = wired.length;
  const mentionedCount = wired.filter(p => results[p.id]?.parsed?.mentioned).length;
  const doneCount = wired.filter(p => results[p.id]?.status === 'done' || results[p.id]?.status === 'error').length;
  const showSummary = wiredCount > 0 && doneCount === wiredCount && !running;

  // Combined cross-model ranking: which brands the models recommend, tallied across all answers.
  const combined = useMemo(() => {
    const tally = new Map();
    wired.forEach((p) => {
      const r = results[p.id];
      if (r?.status !== 'done' || !r.brands) return;
      r.brands.forEach(({ name, rank }) => {
        const key = name.toLowerCase();
        const e = tally.get(key) || { name, models: new Set(), ranks: [] };
        e.models.add(p.id); e.ranks.push(rank);
        tally.set(key, e);
      });
    });
    const youName = (brand?.name || '').toLowerCase();
    return [...tally.values()]
      .map((e) => ({ name: e.name, count: e.models.size, avgRank: e.ranks.reduce((a, b) => a + b, 0) / e.ranks.length, you: !!youName && e.name.toLowerCase() === youName }))
      .sort((a, b) => b.count - a.count || a.avgRank - b.avgRank)
      .slice(0, 8);
  }, [results, wired, brand?.name]);

  return (
    <div className="qi-section">
      <div className="qi-head">
        <div className="eyebrow">
          <span className="db-dot live-pulse" />
          {managedMode
            ? <>Query inspector · {wiredCount} model{wiredCount === 1 ? '' : 's'} live on the server</>
            : <>Query inspector · live · {wiredCount} model{wiredCount === 1 ? '' : 's'} wired</>}
        </div>
        <h3>Ask any question. Watch {wiredCount > 1 ? `${wiredCount} models` : 'the model'} answer at once.</h3>
        <p className="qi-sub">
          {managedMode
            ? `Fires the same prompt at every model AISO has wired server-side. Real APIs, real parallel calls — nothing for you to configure.`
            : `Sends the exact prompt below to every model you've wired. No mock data — real APIs, parallel calls, your keys.`}
        </p>

        {wiredCount === 0 && (
          <div className="qi-empty">
            <span style={{ fontFamily: 'var(--mono)', fontSize: 11, letterSpacing: '0.12em', textTransform: 'uppercase', color: 'var(--fg-3)' }}>
              waiting for managed providers
            </span>
          </div>
        )}

        {wiredCount > 0 && (
          <>
            <form className="qi-input" onSubmit={(e) => { e.preventDefault(); ask(); }}>
              <input
                type="text"
                value={prompt}
                onChange={(e) => setPrompt(e.target.value)}
                placeholder="What would a customer ask AI to discover you?"
                spellCheck={false}
                autoComplete="off"
              />
              <button type="submit" className="qi-ask" disabled={running || !prompt.trim()}>
                {running ? (<><span className="dot-spin" /> Asking…</>) : (<>Ask {wiredCount} model{wiredCount === 1 ? '' : 's'} <Arrow /></>)}
              </button>
            </form>

            {suggestions.length > 0 && (
              <div className="qi-suggestions">
                <span className="qi-sug-label">Try</span>
                {suggestions.map((s, i) => (
                  <button key={i} className="qi-sug" onClick={() => { setPrompt(s); ask(s); }} disabled={running}>{s}</button>
                ))}
              </div>
            )}
          </>
        )}

        {showSummary && (
          <div className="qi-summary">
            <span className="qi-summary-stat">
              <span className="qi-summary-num">{mentionedCount}</span>
              <span className="qi-summary-of">/ {wiredCount}</span>
              <span className="qi-summary-label">models mentioned {brand?.name || 'you'}</span>
            </span>
          </div>
        )}
      </div>

      {showSummary && combined.length > 0 && (
        <div style={{ margin: '4px 0 18px', border: '1px solid var(--line)', borderRadius: 14, padding: '16px 18px', background: 'var(--bg-1)' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 13, gap: 12, flexWrap: 'wrap' }}>
            <span style={{ fontWeight: 600, fontSize: 15 }}>Who the {wiredCount} models recommend</span>
            <span style={{ fontFamily: 'var(--mono)', fontSize: 10.5, color: brand?.name && !combined.some(c => c.you) ? 'var(--warn, #e0a050)' : 'var(--fg-3)', textTransform: 'uppercase', letterSpacing: '0.08em' }}>
              {brand?.name ? (combined.some(c => c.you) ? `${brand.name} ranks here` : `${brand.name} doesn't appear`) : 'combined ranking'}
            </span>
          </div>
          <div style={{ display: 'flex', flexDirection: 'column', gap: 7 }}>
            {combined.map((c, i) => (
              <div key={c.name} style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 12, color: 'var(--fg-3)', width: 16, textAlign: 'right' }}>{i + 1}</span>
                <span style={{ flexShrink: 0, width: 156, fontSize: 13.5, fontWeight: c.you ? 700 : 500, color: c.you ? 'var(--accent)' : 'var(--fg-0)', whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                  {c.name}{c.you && ' ◆'}
                </span>
                <span style={{ flex: 1, height: 6, background: 'rgba(255,255,255,0.07)', borderRadius: 999, overflow: 'hidden' }}>
                  <span style={{ display: 'block', height: '100%', width: `${(c.count / wiredCount) * 100}%`, background: c.you ? 'var(--accent)' : 'var(--accent-grad, var(--accent))', borderRadius: 999 }} />
                </span>
                <span style={{ fontFamily: 'var(--mono)', fontSize: 11.5, color: 'var(--fg-2)', width: 30, textAlign: 'right' }}>{c.count}/{wiredCount}</span>
              </div>
            ))}
          </div>
        </div>
      )}

      {wiredCount > 0 && (
        <div className="qi-grid">
          {wired.map((provider) => {
            const r = results[provider.id];
            const color = `oklch(78% 0.16 ${provider.hue})`;
            return (
              <article key={provider.id} className={`qi-card qi-status-${r?.status || 'idle'}`} style={{ '--qi-color': color, '--qi-hue': provider.hue }}>
                <div className="qi-card-head">
                  <div className="qi-card-id">
                    <span className="qi-dot" style={{ background: color, boxShadow: `0 0 10px ${color}` }} />
                    <span className="qi-card-name">{provider.name}</span>
                  </div>
                  <span className="qi-card-model">{provider.model}</span>
                </div>

                {(!r || r.status === 'idle') && (
                  <div className="qi-card-empty">
                    <span style={{ color: 'var(--fg-3)', fontSize: 12.5, fontStyle: 'italic' }}>waiting</span>
                  </div>
                )}

                {r?.status === 'running' && (
                  <div className="qi-card-running">
                    <div className="qi-shimmer-line" />
                    <div className="qi-shimmer-line" style={{ width: '88%' }} />
                    <div className="qi-shimmer-line" style={{ width: '72%' }} />
                    <div className="qi-shimmer-line" style={{ width: '60%' }} />
                  </div>
                )}

                {r?.status === 'error' && (
                  <div className="qi-card-error">
                    <span className="qi-err-tag">error</span>
                    <p>{r.error}</p>
                  </div>
                )}

                {r?.status === 'done' && (
                  <>
                    <div className="qi-card-meta">
                      {r.parsed?.mentioned ? (
                        <span className="qi-pill qi-pill-yes">✓ mentioned{r.parsed.rank ? ` · rank ${r.parsed.rank}` : ''}</span>
                      ) : (
                        <span className="qi-pill qi-pill-no">✕ not mentioned</span>
                      )}
                      <span className="qi-pill qi-pill-time">{r.elapsed}ms</span>
                    </div>
                    <div className="qi-card-body">
                      {highlightText(r.text, brand?.name, competitors)}
                    </div>
                    {r.brands && r.brands.length > 0 && (
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: 5, marginTop: 11, paddingTop: 11, borderTop: '1px solid var(--line)' }}>
                        <span style={{ fontFamily: 'var(--mono)', fontSize: 10, letterSpacing: '0.1em', textTransform: 'uppercase', color: 'var(--fg-3)', alignSelf: 'center', marginRight: 2 }}>names</span>
                        {r.brands.slice(0, 7).map((b) => {
                          const you = brand?.name && b.name.toLowerCase() === brand.name.toLowerCase();
                          return <span key={b.name} style={{ fontFamily: 'var(--mono)', fontSize: 10.5, color: you ? 'var(--accent)' : 'var(--fg-2)', border: `1px solid ${you ? 'var(--accent)' : 'var(--line)'}`, borderRadius: 999, padding: '2px 8px' }}>{b.name}</span>;
                        })}
                      </div>
                    )}
                  </>
                )}
              </article>
            );
          })}
        </div>
      )}

      {history.length > 0 && (
        <details className="qi-history">
          <summary>Recent questions ({history.length})</summary>
          <div className="qi-history-list">
            {history.slice(0, 8).map(h => (
              <button key={h.id} className="qi-history-item" onClick={() => { setPrompt(h.prompt); ask(h.prompt); }}>
                <span className="qi-h-prompt">"{h.prompt}"</span>
                <span className="qi-h-meta">{new Date(h.at).toLocaleString()}</span>
              </button>
            ))}
          </div>
        </details>
      )}
    </div>
  );
}

function Arrow() { return <svg width="14" height="14" viewBox="0 0 14 14" fill="none"><path d="M2 7h10M8 3l4 4-4 4" stroke="currentColor" strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round"/></svg>; }

Object.assign(window, { QueryInspector });
