// ================================================================
// App root — Agentforce streaming integration
// ================================================================

const { useState, useEffect, useRef } = React;
const { AGENTS, NOTIFICATIONS } = window.LUMEN_DATA;

// Pick which expertise avatar to show based on message content (display only)
function routeAgent(text) {
  const t = text.toLowerCase();
  if (/\b(mulesoft|anypoint|dataweave|cloudhub|integration|middleware|esb)\b/.test(t)) return 'mulesoft';
  if (/\b(salesforce|sfdc|crm|agentforce|apex|lwc|force\.com)\b/.test(t)) return 'salesforce';
  if (/\b(ai|ml|llm|gpt|claude|agent|rag|prompt|model)\b/.test(t)) return 'ai';
  if (/\b(api|rest|soap|raml|openapi|swagger|endpoint)\b/.test(t)) return 'api';
  if (/\b(project|national grid|sap|godaddy|oracle|work|built|shipped)\b/.test(t)) return 'projects';
  if (/\b(contact|email|linkedin|hire|consult|reach|connect|opportunity)\b/.test(t)) return 'connect';
  return 'mulesoft';
}

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "accent": "cobalt",
  "sidebarCollapsed": false,
  "bgMesh": true
}/*EDITMODE-END*/;

const App = () => {
  const [tweaks, setTweaksState] = useState(() => ({
    ...TWEAK_DEFAULTS,
    theme: localStorage.getItem('sk_theme') || TWEAK_DEFAULTS.theme,
  }));
  const [tweaksOpen, setTweaksOpen] = useState(false);
  const [screen, setScreen] = useState(() => {
    // If landed via 404 redirect from a /chat/ URL, start fresh on home
    const redirectedFrom = sessionStorage.getItem('sk_redirect_path');
    if (redirectedFrom) {
      sessionStorage.removeItem('sk_redirect_path');
      return 'home';
    }
    // If the URL is already a /chat/ path (direct load), show chat if we have messages
    if (window.location.pathname.startsWith('/chat')) {
      return localStorage.getItem('sk_messages') &&
        JSON.parse(localStorage.getItem('sk_messages') || '[]').length > 0
        ? 'chat' : 'home';
    }
    return localStorage.getItem('sk_messages') &&
      JSON.parse(localStorage.getItem('sk_messages') || '[]').length > 0
      ? 'chat' : 'home';
  });
  const [settingsOpen, setSettingsOpen] = useState(false);
  const [notifOpen, setNotifOpen] = useState(false);
  const [notifications, setNotifications] = useState(NOTIFICATIONS);

  // Load messages + chat title from localStorage on first render
  const [messages, setMessages] = useState(() => {
    try {
      const saved = JSON.parse(localStorage.getItem('sk_messages') || '[]');
      // Strip any in-progress streaming flag from a previous session
      return saved.map(m => ({ ...m, streaming: false }));
    } catch { return []; }
  });
  const [thinking, setThinking] = useState(null);
  const [chatTitle, setChatTitle] = useState(
    () => localStorage.getItem('sk_chat_title') || 'New thread'
  );

  // Agentforce session — loaded from localStorage so new tabs reuse the same session
  const sessionRef = useRef({
    id: localStorage.getItem('sk_session_id') || null,
    seq: parseInt(localStorage.getItem('sk_session_seq') || '0', 10),
  });

  // Persist messages whenever they change (only when no message is mid-stream)
  useEffect(() => {
    if (messages.some(m => m.streaming)) return;
    try { localStorage.setItem('sk_messages', JSON.stringify(messages)); } catch {}
  }, [messages]);

  // Persist chat title
  useEffect(() => {
    try { localStorage.setItem('sk_chat_title', chatTitle); } catch {}
  }, [chatTitle]);

  // Persist theme preference
  useEffect(() => {
    try { localStorage.setItem('sk_theme', tweaks.theme); } catch {}
  }, [tweaks.theme]);

  // Sync screen → URL
  useEffect(() => {
    if (screen === 'chat') {
      const sid = sessionRef.current.id;
      const target = `/chat/${sid || 'session'}`;
      if (window.location.pathname !== target) history.pushState(null, '', target);
    } else {
      if (window.location.pathname !== '/') history.pushState(null, '', '/');
    }
  }, [screen]);

  // Browser back / forward
  useEffect(() => {
    const onPop = () => {
      setScreen(window.location.pathname.startsWith('/chat') ? 'chat' : 'home');
    };
    window.addEventListener('popstate', onPop);
    return () => window.removeEventListener('popstate', onPop);
  }, []);

  // ---------- tweaks ----------
  const setTweaks = (next) => {
    setTweaksState(next);
    try { window.parent.postMessage({ type: '__edit_mode_set_keys', edits: next }, '*'); } catch {}
  };

  // ---------- edit mode protocol ----------
  useEffect(() => {
    const onMsg = (e) => {
      if (e.data?.type === '__activate_edit_mode') setTweaksOpen(true);
      if (e.data?.type === '__deactivate_edit_mode') setTweaksOpen(false);
    };
    window.addEventListener('message', onMsg);
    try { window.parent.postMessage({ type: '__edit_mode_available' }, '*'); } catch {}
    return () => window.removeEventListener('message', onMsg);
  }, []);

  // ---------- apply theme ----------
  useEffect(() => {
    document.documentElement.dataset.theme = tweaks.theme;
    document.documentElement.style.setProperty('--accent', window.ACCENT_MAP[tweaks.accent]);
    document.documentElement.style.setProperty('--accent-soft', window.ACCENT_MAP[tweaks.accent].replace(')', ' / 0.10)'));
    document.documentElement.style.setProperty('--accent-glow', window.ACCENT_MAP[tweaks.accent].replace(')', ' / 0.18)'));
  }, [tweaks.theme, tweaks.accent]);

  const formatTime = () => new Date().toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });

  const nextSeq = () => {
    sessionRef.current.seq += 1;
    try { localStorage.setItem('sk_session_seq', sessionRef.current.seq); } catch {}
    return sessionRef.current.seq;
  };

  // Create a new Agentforce session via /api/session and persist it
  const createSession = async () => {
    try {
      const res = await fetch('/api/session', { method: 'POST' });
      if (!res.ok) throw new Error(`Session creation failed: ${res.status}`);
      const { sessionId } = await res.json();
      sessionRef.current = { id: sessionId, seq: 0 };
      try {
        localStorage.setItem('sk_session_id', sessionId);
        localStorage.setItem('sk_session_seq', '0');
        if (window.location.pathname.startsWith('/chat')) {
          history.replaceState(null, '', `/chat/${sessionId}`);
        }
      } catch {}
    } catch (e) {
      console.error('Failed to create session:', e.message);
    }
  };

  // Create session on mount if none exists
  useEffect(() => {
    if (!sessionRef.current.id) createSession();
  }, []);

  // ---------- send message with Agentforce streaming ----------
  const sendMessage = async (text, mentioned, fromHome = false) => {
    if (!text.trim()) return;

    if (fromHome) setScreen('chat');
    if (messages.length === 0) {
      setChatTitle(text.length > 40 ? text.slice(0, 40) + '…' : text);
    }

    setMessages(m => [...m, { role: 'user', content: text, time: formatTime() }]);

    const agentId = mentioned?.id || routeAgent(text);
    const agent = AGENTS.find(a => a.id === agentId);
    const msgId = `msg-${Date.now()}`;

    setThinking(agent);

    // Ensure session exists before sending
    if (!sessionRef.current.id) await createSession();

    try {
      const res = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          message: text,
          sessionId: sessionRef.current.id,
          sequenceId: nextSeq(),
        }),
      });

      if (!res.ok) throw new Error(`HTTP ${res.status}`);

      const reader = res.body.getReader();
      const decoder = new TextDecoder();
      let buf = '';
      let eventType = '';
      let content = '';
      let firstChunk = true;

      while (true) {
        const { done, value } = await reader.read();
        if (done) break;

        buf += decoder.decode(value, { stream: true });
        const lines = buf.split('\n');
        buf = lines.pop() ?? '';

        for (const line of lines) {
          if (line.startsWith('event:')) {
            eventType = line.slice(6).trim();
          } else if (line.startsWith('data:')) {
            const raw = line.slice(5).trim();
            if (!raw) continue;
            try {
              const payload = JSON.parse(raw);

              if (eventType === 'chunk') {
                if (firstChunk) {
                  firstChunk = false;
                  setThinking(null);
                  // Add the streaming message placeholder on first chunk
                  setMessages(m => [...m, {
                    role: 'agent', agent: agent.id,
                    content: payload.text, time: formatTime(),
                    id: msgId, streaming: true,
                  }]);
                  content = payload.text;
                } else {
                  content += payload.text;
                  setMessages(m => m.map(msg =>
                    msg.id === msgId ? { ...msg, content } : msg
                  ));
                }

              } else if (eventType === 'done') {
                setMessages(m => m.map(msg =>
                  msg.id === msgId ? { ...msg, streaming: false } : msg
                ));

              } else if (eventType === 'error') {
                // Show the real Salesforce error in chat for visibility
                setThinking(null);
                setMessages(m => [...m, {
                  role: 'agent', agent: agent.id, id: msgId,
                  content: `⚠️ **Agent error:** ${payload.message || 'Unknown error'}`,
                  time: formatTime(),
                }]);
                return; // exit sendMessage — don't show generic fallback
              }
            } catch (parseErr) {
              if (eventType === 'error') throw parseErr;
            }
          }
        }
      }

      // Ensure streaming flag is cleared even if END_OF_TURN wasn't received
      if (!firstChunk) {
        setMessages(m => m.map(msg =>
          msg.id === msgId ? { ...msg, streaming: false } : msg
        ));
      } else {
        // No chunks at all — show fallback
        setThinking(null);
        setMessages(m => [...m, {
          role: 'agent', agent: agent.id, id: msgId,
          content: fallbackResponse(agent),
          time: formatTime(),
        }]);
      }

    } catch (e) {
      setThinking(null);
      setMessages(m => {
        const existing = m.find(msg => msg.id === msgId);
        if (existing) {
          return m.map(msg => msg.id === msgId
            ? { ...msg, content: msg.content || fallbackResponse(agent), streaming: false }
            : msg
          );
        }
        return [...m, { role: 'agent', agent: agent.id, id: msgId, content: fallbackResponse(agent), time: formatTime() }];
      });
    }
  };

  const fallbackResponse = (agent) =>
    `Thanks for reaching out! Sai Krishna specialises in **${agent.name}** — ${agent.desc}\n\n` +
    `**Key skills:** ${agent.skills.join(', ')}\n\n` +
    `Reach out directly via [LinkedIn](https://linkedin.com/in/saikrishna-durisala).`;

  const handleHomeSend = (text, mentioned) => {
    if (!text.trim()) {
      if (mentioned) setScreen('chat');
      return;
    }
    sendMessage(text, mentioned, true);
  };

  // Sidebar expertise area clicked — navigate to chat and send preset prompt
  const handleAgentClick = (agent) => {
    sendMessage(agent.prompt, agent, true);
  };

  const newThread = () => {
    setMessages([]);
    setChatTitle('New thread');
    sessionRef.current = { id: null, seq: 0 };
    try {
      localStorage.removeItem('sk_session_id');
      localStorage.removeItem('sk_session_seq');
      localStorage.removeItem('sk_messages');
      localStorage.removeItem('sk_chat_title');
    } catch {}
    history.replaceState(null, '', '/chat/new');
    createSession(); // pre-warm a fresh session
  };

  const onMarkAllRead = () => setNotifications(notifications.map(n => ({ ...n, unread: false })));
  const unreadCount = notifications.filter(n => n.unread).length;

  const scrollToSection = (id) => {
    const el = document.getElementById(id);
    if (el) el.scrollIntoView({ behavior: 'smooth', block: 'start' });
  };

  return (
    <>
      {tweaks.bgMesh && <div className="app-bg" />}
      <div className="app" data-sidebar={tweaks.sidebarCollapsed ? 'collapsed' : 'open'}>
        <Sidebar
          collapsed={tweaks.sidebarCollapsed}
          onToggleCollapse={() => setTweaks({ ...tweaks, sidebarCollapsed: !tweaks.sidebarCollapsed })}
          currentScreen={screen}
          onNavigate={(s) => { setScreen(s); }}
          onAgentClick={handleAgentClick}
          onOpenSettings={() => setSettingsOpen(true)}
          agents={AGENTS}
          activeAgentId={thinking?.id}
        />
        <main className="main">
          <div className="topbar">
            <div className="topbar-title">
              {screen === 'home' ? (
                <nav className="topbar-nav">
                  <span className="topbar-nav-link" onClick={() => scrollToSection('section-expertise')}>Expertise</span>
                  <span className="topbar-nav-link" onClick={() => scrollToSection('section-timeline')}>Timeline</span>
                  <span className="topbar-nav-link" onClick={() => scrollToSection('section-highlights')}>Highlights</span>
                  <span className="topbar-nav-link" onClick={() => scrollToSection('section-contact')}>Contact</span>
                </nav>
              ) : (
                <><Icon name="message-square" style={{ color: 'var(--ink-mute)' }} /><span className="topbar-crumb">Ask me</span><span style={{ color: 'var(--ink-faint)' }}>/</span><span>{chatTitle}</span></>
              )}
            </div>
            <div className="topbar-actions">
              {screen === 'chat' && (
                <div className="icon-btn" title="New thread" onClick={newThread}>
                  <Icon name="plus" />
                </div>
              )}
              <div className="icon-btn"
                   title={tweaks.theme === 'dark' ? 'Light mode' : 'Dark mode'}
                   onClick={() => setTweaks({ ...tweaks, theme: tweaks.theme === 'dark' ? 'light' : 'dark' })}>
                <Icon name={tweaks.theme === 'dark' ? 'sun' : 'moon'} />
              </div>
              <div className="icon-btn" onClick={() => setTweaksOpen(!tweaksOpen)} title="Personalize">
                <Icon name="sliders" />
              </div>
            </div>

          </div>

          {screen === 'home' ? (
            <HomeScreen agents={AGENTS} onSendPrompt={handleHomeSend} />
          ) : (
            <ChatScreen
              messages={messages}
              onSendMessage={(t, m) => sendMessage(t, m)}
              agents={AGENTS}
              isThinking={thinking}
              onNewChat={newThread}
            />
          )}
        </main>
      </div>

      {settingsOpen && (
        <SettingsModal
          onClose={() => setSettingsOpen(false)}
          theme={tweaks.theme}
          onThemeChange={(t) => setTweaks({ ...tweaks, theme: t })}
          density={'comfortable'}
          onDensityChange={() => {}}
          accent={tweaks.accent}
          onAccentChange={(a) => setTweaks({ ...tweaks, accent: a })}
        />
      )}

      {notifOpen && (
        <NotificationsPanel
          onClose={() => setNotifOpen(false)}
          agents={AGENTS}
          notifications={notifications}
          onMarkAllRead={onMarkAllRead}
        />
      )}

      {tweaksOpen && (
        <TweaksPanel tweaks={tweaks} setTweaks={setTweaks} onClose={() => setTweaksOpen(false)} />
      )}
    </>
  );
};

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<App />);
