// In-app AI assistant — answers product/how-to questions and live-data questions.
// Powered by window.claude.complete (Haiku). Knows the CRM's structure and a
// computed snapshot of the data the current user can see.

function Assistant({ deals, showrooms, reps, stages, contacts, currentUser, access, view, counts }) {
  const [open, setOpen] = React.useState(false);
  const [input, setInput] = React.useState('');
  const [busy, setBusy] = React.useState(false);
  const [messages, setMessages] = React.useState([]); // { role:'user'|'bot', content }
  const bodyRef = React.useRef(null);
  const taRef = React.useRef(null);

  const T = window.T || ((k) => k);
  const TODAY = (window.SALES_DATA && window.SALES_DATA.TODAY) || 'today';
  const repWord = T('reps') || 'designers';
  const locWord = T('locations') || 'showrooms';

  const money = (n) => {
    if (n == null || isNaN(n)) return '$0';
    const a = Math.abs(n);
    if (a >= 1e6) return '$' + (n / 1e6).toFixed(2).replace(/\.?0+$/, '') + 'M';
    if (a >= 1e3) return '$' + Math.round(n / 1e3) + 'k';
    return '$' + Math.round(n);
  };
  const stageLabel = (id) => (stages.find((s) => s.id === id) || {}).label || id;
  const showName = (id) => (showrooms.find((s) => s.id === id) || {}).name || id;

  // ---- Live data snapshot (recomputed when inputs change) ----------------
  const snapshot = React.useMemo(() => {
    const active = deals.filter((d) => d.stage !== 'sold' && d.stage !== 'lost');
    const won = deals.filter((d) => d.stage === 'sold');
    const lost = deals.filter((d) => d.stage === 'lost');
    const stuck = active.filter((d) => (d.lastActivityDaysAgo || 0) > 21);
    const sum = (arr) => arr.reduce((t, d) => t + (d.value || 0), 0);
    const pipelineValue = sum(active);
    const weighted = active.reduce((t, d) => {
      const p = (stages.find((s) => s.id === d.stage) || {}).prob || 0;
      return t + (d.value || 0) * p;
    }, 0);
    const wonValue = sum(won);
    const winRate = won.length + lost.length > 0 ? Math.round((won.length / (won.length + lost.length)) * 100) : 0;

    const byStage = stages.map((s) => {
      const ds = deals.filter((d) => d.stage === s.id);
      return `  - ${s.label}: ${ds.length} deals, ${money(sum(ds))}`;
    }).join('\n');

    const byShowroom = showrooms.map((s) => {
      const ds = deals.filter((d) => d.showroom === s.id);
      const a = ds.filter((d) => d.stage !== 'sold' && d.stage !== 'lost');
      const w = ds.filter((d) => d.stage === 'sold');
      return `  - ${s.name} (${s.state}): ${ds.length} deals · open pipeline ${money(sum(a))} · won ${money(sum(w))} (${w.length}) · target ${money(s.target)}`;
    }).join('\n');

    const byRep = reps.map((r) => {
      const ds = deals.filter((d) => d.rep === r.id);
      if (!ds.length) return null;
      const a = ds.filter((d) => d.stage !== 'sold' && d.stage !== 'lost');
      const w = ds.filter((d) => d.stage === 'sold');
      const st = a.filter((d) => (d.lastActivityDaysAgo || 0) > 21);
      return `  - ${r.name}: ${ds.length} deals · open ${money(sum(a))} · won ${money(sum(w))} (${w.length}) · ${st.length} stuck · quota ${money(r.quota)}`;
    }).filter(Boolean).join('\n');

    const topActive = [...active].sort((a, b) => (b.value || 0) - (a.value || 0)).slice(0, 12)
      .map((d) => `  - ${d.customer} · ${money(d.value)} · ${stageLabel(d.stage)} · ${d.repName} · ${showName(d.showroom)} · ${d.lastActivityDaysAgo}d idle`).join('\n');

    const oldestStuck = [...stuck].sort((a, b) => (b.lastActivityDaysAgo || 0) - (a.lastActivityDaysAgo || 0)).slice(0, 12)
      .map((d) => `  - ${d.customer} · ${money(d.value)} · ${stageLabel(d.stage)} · ${d.repName} · ${showName(d.showroom)} · ${d.lastActivityDaysAgo}d idle`).join('\n');

    // Compact full register so arbitrary lookups are possible
    const register = deals.map((d) =>
      `${d.customer}|${stageLabel(d.stage)}|${money(d.value)}|${d.repName}|${showName(d.showroom)}|${d.lastActivityDaysAgo}d|${d.product || '—'}`
    ).join('\n');

    return `Scope: the data below is the COMPLETE set ${currentUser.name} (${currentUser.title}, role: ${(access && access.roleLabel) || 'user'}) is authorised to see — ${(access && access.scopeText) || 'their permitted data'}. It already excludes anything outside their authority.
Totals: ${deals.length} deals — ${active.length} active, ${won.length} sold, ${lost.length} lost.
Open pipeline value: ${money(pipelineValue)} · weighted (probability-adjusted): ${money(weighted)}.
Closed-won value: ${money(wonValue)} · win rate: ${winRate}% (won ÷ won+lost).
Stuck deals (active, no activity in 21+ days): ${stuck.length}.
Avg active deal size: ${money(active.length ? pipelineValue / active.length : 0)}.

By stage:
${byStage}

By ${locWord}:
${byShowroom}

By ${repWord}:
${byRep}

Largest open deals:
${topActive}

Most stuck deals:
${oldestStuck}

FULL REGISTER (customer | stage | value | designer | ${locWord.replace(/s$/, '')} | days idle | product):
${register}`;
  }, [deals, showrooms, reps, stages, currentUser]);

  const KNOWLEDGE = `You are the built-in AI assistant inside "Stagevo", a sales-pipeline CRM used by a kitchen, laundry & cabinetry retailer that sells through physical ${locWord}. Help users two ways: (1) explain how the CRM works and what fields/metrics mean, and (2) answer questions about their live data using the snapshot provided.

PAGES (left sidebar):
- Overview — KPIs (pipeline value, closed-won, win rate, stuck), pipeline-by-stage and conversion funnel, what needs attention.
- Contacts — every customer/lead, lifecycle stage, claim unassigned inbound leads.
- Calendar — design appointments, onsite visits, follow-ups and tasks.
- Pipeline — kanban board; drag deals between stages.
- All Deals — sortable/filterable register of every deal (quote).
- Aging & Stuck — deals with no recent activity, grouped by age, with risk ratings.
- ${locWord} — per-location performance, ranking and comparison.
- Sales ${repWord} — leaderboard: quota progress, won value, stuck counts.
- Reports — lead source, conversion timing and other breakdowns.
- Company KPIs — tracked metrics vs target with progress bars.
- Forecast — expected deposits by period vs target.
- ROI Calculator — models time/revenue impact of the CRM.
- Admin (admin only): Team & Access, Manage ${locWord}, Workspace & Industry, Sales Targets, KPI Targets, Automations, Settings, Data Import.

STAGES (a deal moves through these):
- Possible Sale — early lead/enquiry (~25% likely).
- In Progress — actively quoting/designing (~50%).
- On Hold — paused by the customer (~15%).
- Sold — won, deposit taken (100%).
- Lost — dead (0%).

KEY FIELDS & TERMS:
- Deal / quote: one opportunity, identified by a quote number; has a customer, product (Kitchen, Laundry, etc.), value (AUD), assigned designer and ${locWord.replace(/s$/, '')}.
- Value: quoted job value in AUD.
- Pipeline value: total value of all active (not Sold/Lost) deals. Weighted pipeline multiplies each by its stage probability.
- Win rate: Sold ÷ (Sold + Lost).
- Onsite visit: whether the designer has measured up at the customer's home.
- Forecast deposit month: month the deposit is expected — drives Forecast.
- Last activity / idle days: days since the last logged note/call/email. "Stuck" = an active deal with 21+ idle days.
- Designer (a.k.a. sales rep): the person who owns the deal. Quota: their target won value.

COMMON HOW-TOs:
- New lead/deal: "New lead" button (top-right). New contact: "New contact".
- Move a deal's stage: drag its card on the Pipeline board, or open the deal and change Stage.
- Claim an inbound lead: Contacts page → "Claim" on an unassigned lead.
- Export: "Export CSV" (top-right, leadership).
- Switch ${locWord.replace(/s$/, '')}: the showroom switcher bar under the top bar filters the whole app.
- Filters (rep, stage, age, past-forecast, stuck) sit in the filter bar on Pipeline/All Deals/Aging.`;

  const RULES = `INSTRUCTIONS:
- Be concise and friendly. Default to 1–4 short sentences or a tight bulleted list.
- For data questions, compute from the snapshot and give the actual numbers; name specific deals/${repWord}/${locWord} when useful.
- All money is AUD. Today's date is ${TODAY}.
- ACCESS CONTROL (critical): the signed-in user is a ${(access && access.roleLabel) || 'user'} and may only see ${(access && access.scopeText) || 'their permitted data'}. The snapshot already contains ONLY that. NEVER infer, estimate, or reveal anything outside it — e.g. other designers' deals/quotas, other showrooms, or company-wide totals the user isn't entitled to. If asked for such data, briefly say it isn't available at their access level and stop. Do not reveal another person's contact details or private notes beyond what's in the snapshot.
${(access && !access.canSeeAll) ? "- Admin areas (Team & Access, Settings, Data Import, Sales Targets, KPI Targets) are admin-only; if asked, say they're restricted to admins rather than describing their data.\n" : ''}- If something isn't in the snapshot or you're unsure, say so and suggest where in the CRM to look — never invent figures.
- Use **bold** for key numbers. Keep it skimmable. No preamble like "Sure!" — answer directly.`;

  const SUGGESTIONS = [
    'How many deals are stuck right now?',
    "What's our win rate?",
    `Which ${locWord.replace(/s$/, '')} has the most open pipeline?`,
    "What does a deal being “stuck” mean?",
    'How do I add a new lead?',
  ];

  React.useEffect(() => {
    if (bodyRef.current) bodyRef.current.scrollTop = bodyRef.current.scrollHeight;
  }, [messages, busy, open]);

  // Reset the conversation whenever the signed-in identity changes, so answers
  // scoped to one user's authority never carry over to another.
  React.useEffect(() => {
    setMessages([]);
    setBusy(false);
    setInput('');
  }, [currentUser.id]);

  React.useEffect(() => {
    if (open && taRef.current) taRef.current.focus();
  }, [open]);

  const grow = (el) => { el.style.height = 'auto'; el.style.height = Math.min(el.scrollHeight, 96) + 'px'; };

  async function send(text) {
    const q = (text != null ? text : input).trim();
    if (!q || busy) return;
    setInput('');
    if (taRef.current) taRef.current.style.height = 'auto';
    const next = [...messages, { role: 'user', content: q }];
    setMessages(next);
    setBusy(true);
    try {
      const convo = [
        { role: 'user', content: `${KNOWLEDGE}\n\n=== LIVE DATA SNAPSHOT (as of ${TODAY}) ===\n${snapshot}\n\n${RULES}\n\nReply only with "Ready." and then wait for my questions.` },
        { role: 'assistant', content: 'Ready.' },
        ...next.map((m) => ({ role: m.role === 'bot' ? 'assistant' : 'user', content: m.content })),
      ];
      const reply = await window.claude.complete({ messages: convo });
      setMessages((m) => [...m, { role: 'bot', content: (reply || '').trim() || "I couldn't generate a response — please try again." }]);
    } catch (e) {
      setMessages((m) => [...m, { role: 'bot', content: "I hit a snag reaching the AI service (it may be rate-limited). Give it a moment and try again." }]);
    } finally {
      setBusy(false);
    }
  }

  if (!open) {
    return (
      <button className="ai-launcher" onClick={() => setOpen(true)} aria-label="Open AI assistant">
        <span className="ai-spark"><Icon name="spark" size={15} color="#fff"/></span>
        Ask AI
      </button>
    );
  }

  return (
    <div className="ai-panel" role="dialog" aria-label="AI assistant">
      <div className="ai-head">
        <div className="ai-avatar"><Icon name="spark" size={18}/></div>
        <div style={{ minWidth: 0 }}>
          <div className="ai-title">Stagevo Assistant</div>
          <div className="ai-sub"><span className="ai-dot"></span> {(access && access.canSeeAll) ? 'Knows your CRM \u0026 live data' : 'Answers within your access'}</div>
        </div>
        <button className="ai-close" onClick={() => setOpen(false)} aria-label="Close"><Icon name="close" size={16}/></button>
      </div>

      <div className="ai-body" ref={bodyRef}>
        {messages.length === 0 && (
          <React.Fragment>
            <div className="ai-msg bot">
              <span className="ai-msg-av"><Icon name="spark" size={14}/></span>
              <div className="ai-bubble">
                <p>Hi {currentUser.name.split(' ')[0]} 👋 I'm your Stagevo assistant.</p>
                <p>Ask me how anything in the CRM works, what a field means, or for a quick read on your data. Try one of these:</p>
              </div>
            </div>
            <div className="ai-suggest">
              {SUGGESTIONS.map((s) => (
                <button key={s} className="ai-chip" onClick={() => send(s)}>{s}</button>
              ))}
            </div>
          </React.Fragment>
        )}

        {messages.map((m, i) => (
          <div key={i} className={`ai-msg ${m.role}`}>
            <span className="ai-msg-av">{m.role === 'bot' ? <Icon name="spark" size={14}/> : currentUser.name.split(' ').map((p) => p[0]).slice(0, 2).join('')}</span>
            <div className="ai-bubble" dangerouslySetInnerHTML={{ __html: renderMarkdown(m.content) }}/>
          </div>
        ))}

        {busy && (
          <div className="ai-msg bot">
            <span className="ai-msg-av"><Icon name="spark" size={14}/></span>
            <div className="ai-bubble"><span className="ai-typing"><span></span><span></span><span></span></span></div>
          </div>
        )}
      </div>

      <div className="ai-foot">
        <div className="ai-input-row">
          <textarea
            ref={taRef}
            rows={1}
            placeholder="Ask about the CRM or your data…"
            value={input}
            onChange={(e) => { setInput(e.target.value); grow(e.target); }}
            onKeyDown={(e) => { if (e.key === 'Enter' && !e.shiftKey) { e.preventDefault(); send(); } }}
          />
          <button className="ai-send" disabled={!input.trim() || busy} onClick={() => send()} aria-label="Send">
            <Icon name="arrow-up" size={16} color="#fff"/>
          </button>
        </div>
        <div className="ai-disclaimer">AI can make mistakes — double-check important figures in the data.</div>
      </div>
    </div>
  );
}

// Tiny, safe markdown → HTML for assistant replies (bold, lists, paragraphs, code).
function renderMarkdown(src) {
  const esc = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
  const inline = (s) => esc(s)
    .replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>')
    .replace(/`([^`]+)`/g, '<code>$1</code>');
  const lines = (src || '').split('\n');
  let html = '';
  let list = null; // 'ul' or 'ol'
  const closeList = () => { if (list) { html += `</${list}>`; list = null; } };
  for (let raw of lines) {
    const line = raw.trim();
    if (!line) { closeList(); continue; }
    const bullet = line.match(/^[-*•]\s+(.*)/);
    const num = line.match(/^\d+[.)]\s+(.*)/);
    if (bullet) {
      if (list !== 'ul') { closeList(); html += '<ul>'; list = 'ul'; }
      html += `<li>${inline(bullet[1])}</li>`;
    } else if (num) {
      if (list !== 'ol') { closeList(); html += '<ol>'; list = 'ol'; }
      html += `<li>${inline(num[1])}</li>`;
    } else {
      closeList();
      html += `<p>${inline(line)}</p>`;
    }
  }
  closeList();
  return html;
}

window.Assistant = Assistant;
