// Reuse the existing app.js logic - this was copied over from chat/public/app.js
// In a production step, you'd avoid duplication: use a symlink or keep a single source

const state = {
  sessions: [],
  currentSessionId: null,
  models: [],
  pollingTimer: null,
  mode: 'agent', // agent or plan
  showingHome: false,
  cliOptions: ['opencode', 'gemini-cli'],
  currentCli: 'opencode',
  activeStreams: new Map(), // Track active SSE connections
  opencodeStatus: null,
};

const el = {
  sessionList: document.getElementById('session-list'),
  chatArea: document.getElementById('chat-area'),
  chatTitle: document.getElementById('chat-title'),
  sessionId: document.getElementById('session-id'),
  sessionModel: document.getElementById('session-model'),
  sessionPending: document.getElementById('session-pending'),
  queueIndicator: document.getElementById('queue-indicator'),
  cliSelect: document.getElementById('cli-select'),
  modelSelect: document.getElementById('model-select'),
  modeSelect: document.getElementById('mode-select'),
  customModelLabel: document.getElementById('custom-model-label'),
  customModelInput: document.getElementById('custom-model-input'),
  newChat: document.getElementById('new-chat'),
  homeBtn: document.getElementById('home-btn'),
  homeView: document.getElementById('home-view'),
  homeSessionList: document.getElementById('home-session-list'),
  sessionMeta: document.getElementById('session-meta'),
  messageInput: document.getElementById('message-input'),
  sendBtn: document.getElementById('send-btn'),
  statusLine: document.getElementById('status-line'),
  quickButtons: document.querySelectorAll('[data-quick]'),
  gitButtons: document.querySelectorAll('[data-git]'),
  gitOutput: document.getElementById('git-output'),
  diagnosticsButton: document.getElementById('diagnostics-button'),
  commitMessage: document.getElementById('commit-message'),
  githubButton: document.getElementById('github-button'),
  githubModal: document.getElementById('github-modal'),
  githubClose: document.getElementById('github-close'),
  modalCommitMessage: document.getElementById('modal-commit-message'),
};

function setStatus(msg) { el.statusLine.textContent = msg || ''; }

async function api(path, options = {}) {
  const res = await fetch(path, { headers: { 'Content-Type': 'application/json' }, ...options });
  const text = await res.text();
  const json = text ? JSON.parse(text) : {};
  if (!res.ok) {
    const err = new Error(json.error || res.statusText);
    // include stdout/stderr if returned by the server
    if (json.stdout) err.stdout = json.stdout;
    if (json.stderr) err.stderr = json.stderr;
    throw err;
  }
  return json;
}

function populateCliSelect() {
  if (!el.cliSelect) return;
  el.cliSelect.innerHTML = '';
  state.cliOptions.forEach((cli) => {
    const opt = document.createElement('option');
    opt.value = cli;
    opt.textContent = cli.toUpperCase();
    el.cliSelect.appendChild(opt);
  });
  el.cliSelect.value = state.currentCli;
}

function renderSessions() {
  el.sessionList.innerHTML = '';
  if (!state.sessions.length) {
    el.sessionList.innerHTML = '<div class="muted">No sessions yet.</div>';
    return;
  }
  state.sessions.forEach((session) => {
    const div = document.createElement('div');
    div.className = `session-item ${session.id === state.currentSessionId ? 'active' : ''}`;
    div.innerHTML = `
      <div class="session-title">${session.title || 'Chat'}</div>
      <div class="session-meta">
        <span class="badge">${session.cli || 'opencode'}</span>
        <span class="badge">${session.model}</span>
        <span class="badge ${session.pending ? 'accent' : ''}">${session.pending || 0} queued</span>
      </div>
      <div class="session-delete">
        <button title="Delete" class="delete-btn">🗑</button>
        <div class="delete-menu" role="dialog" aria-label="Confirm delete chat">
          <div class="title">Delete this chat?</div>
          <div class="actions">
            <button class="cancel-delete ghost">Cancel</button>
            <button class="confirm-delete">Delete</button>
          </div>
        </div>
      </div>
    `;
    div.addEventListener('click', () => selectSession(session.id));
    const deleteBtn = div.querySelector('.delete-btn');
    const cancelBtn = div.querySelector('.cancel-delete');
    const confirmBtn = div.querySelector('.confirm-delete');
    if (deleteBtn) {
      deleteBtn.addEventListener('click', (e) => {
        e.stopPropagation();
        const isOpen = div.classList.toggle('show-delete-menu');
        if (isOpen) {
          document.querySelectorAll('.session-item.show-delete-menu').forEach((item) => { if (item !== div) item.classList.remove('show-delete-menu'); });
          const onDocClick = (ev) => { if (!div.contains(ev.target)) div.classList.remove('show-delete-menu'); };
          setTimeout(() => document.addEventListener('click', onDocClick, { once: true }), 0);
        }
      });
    }
    if (cancelBtn) cancelBtn.addEventListener('click', (e) => { e.stopPropagation(); div.classList.remove('show-delete-menu'); });
    if (confirmBtn) confirmBtn.addEventListener('click', async (e) => {
      e.stopPropagation();
      try {
        await api(`/api/sessions/${session.id}`, { method: 'DELETE' });
        state.sessions = state.sessions.filter((s) => s.id !== session.id);
        if (state.currentSessionId === session.id) {
          if (state.sessions.length) await selectSession(state.sessions[0].id);
          else { state.currentSessionId = null; el.sessionList.innerHTML = ''; await createSession(); }
        } else {
          renderSessions();
        }
        setStatus('Chat deleted');
      } catch (error) { setStatus(`Failed to delete chat: ${error.message}`); }
    });
    el.sessionList.appendChild(div);
  });
}

function renderSessionMeta(session) {
  el.sessionId.textContent = session.id;
  el.sessionModel.textContent = `${session.cli || 'opencode'} / ${session.model}`;
  el.sessionPending.textContent = session.pending || 0;
  el.queueIndicator.textContent = session.pending ? `${session.pending} queued` : 'Idle';
  el.queueIndicator.style.borderColor = session.pending ? 'var(--accent)' : 'var(--border)';
  el.chatTitle.textContent = session.title || 'Chat';
  if (session.cli && el.cliSelect && el.cliSelect.value !== session.cli) {
    el.cliSelect.value = session.cli;
    state.currentCli = session.cli;
  }
  if (session.model && el.modelSelect.value !== session.model) el.modelSelect.value = session.model;
}

function renderMessages(session) {
  el.chatArea.innerHTML = '';
  if (!session.messages || !session.messages.length) {
    el.chatArea.innerHTML = '<div class="muted empty-message">Send a message to start the conversation.</div>';
    return;
  }
  session.messages.forEach((msg) => {
    const status = msg.status || 'done';
    const userCard = document.createElement('div');
    userCard.className = 'message user';
    const userMeta = document.createElement('div');
    userMeta.className = 'meta';
    userMeta.innerHTML = `
      <span>You</span>
      <span class="badge">${msg.model || session.model}</span>
      <span class="status-chip ${status}">${status}</span>
    `;
    const userBody = document.createElement('div');
    userBody.className = 'body';
    userBody.appendChild(renderContentWithTodos(msg.content || ''));
    userCard.appendChild(userMeta);
    userCard.appendChild(userBody);
    // Attachments
    if (Array.isArray(msg.attachments) && msg.attachments.length) {
      const attachWrap = document.createElement('div');
      attachWrap.className = 'attachments';
      msg.attachments.forEach((a) => {
        if (a && a.url && (a.type || '').startsWith('image/')) {
          const img = document.createElement('img');
          img.className = 'attachment-image';
          img.src = a.url;
          img.alt = a.name || 'image';
          img.style.maxWidth = '400px';
          img.style.display = 'block';
          img.style.marginTop = '8px';
          attachWrap.appendChild(img);
        }
      });
      userCard.appendChild(attachWrap);
    }
    el.chatArea.appendChild(userCard);
    if (msg.reply || msg.error || (status === 'running' && msg.partialOutput)) {
      const assistantCard = document.createElement('div');
      assistantCard.className = 'message assistant';
      const assistantMeta = document.createElement('div');
      assistantMeta.className = 'meta';
      assistantMeta.innerHTML = `<span>${(session.cli || 'opencode').toUpperCase()}</span>`;
      // Add a small raw toggle button for diagnostics
      const rawBtn = document.createElement('button');
      rawBtn.className = 'ghost';
      rawBtn.style.marginLeft = '8px';
      rawBtn.textContent = 'Raw';
      assistantMeta.appendChild(rawBtn);
      const assistantBody = document.createElement('div');
      assistantBody.className = 'body';
      assistantBody.appendChild(renderContentWithTodos(msg.reply || msg.partialOutput || msg.opencodeSummary || ''));
      assistantCard.appendChild(assistantMeta);
      assistantCard.appendChild(assistantBody);
        if (Array.isArray(msg.attachments) && msg.attachments.length) {
          const attachWrap = document.createElement('div');
          attachWrap.className = 'attachments';
          msg.attachments.forEach((a) => {
            if (a && a.url && (a.type || '').startsWith('image/')) {
              const img = document.createElement('img');
              img.className = 'attachment-image';
              img.src = a.url;
              img.alt = a.name || 'image';
              img.style.maxWidth = '400px';
              img.style.display = 'block';
              img.style.marginTop = '8px';
              attachWrap.appendChild(img);
            }
          });
          assistantCard.appendChild(attachWrap);
        }
      if (msg.error) {
        const err = document.createElement('div');
        err.className = 'body';
        err.style.color = 'var(--danger)';
        err.textContent = msg.error;
        assistantCard.appendChild(err);
      }
      if ((!msg.reply || !msg.reply.length) && (!msg.partialOutput || !msg.partialOutput.length) && msg.opencodeSummary) {
        const summary = document.createElement('div');
        summary.className = 'body';
        summary.style.color = 'var(--muted)';
        summary.textContent = `Opencode output: ${msg.opencodeSummary}`;
        assistantCard.appendChild(summary);
      }
      // Raw output container
      const rawPre = document.createElement('pre');
      rawPre.className = 'raw-output muted';
      rawPre.style.display = 'none';
      rawPre.textContent = [(msg.partialOutput || ''), (msg.opencodeSummary || '')].filter(Boolean).join('\n\n');
      assistantCard.appendChild(rawPre);
      rawBtn.addEventListener('click', () => { rawPre.style.display = rawPre.style.display === 'none' ? 'block' : 'none'; });
      el.chatArea.appendChild(assistantCard);
    }
  });
  el.chatArea.scrollTop = el.chatArea.scrollHeight;
}

// Helper: render text content and convert markdown task-list lines to actual checkboxes
function renderContentWithTodos(text) {
  const wrapper = document.createElement('div');
  if (!text) return document.createTextNode('');
  const processedText = String(text).replace(/\.\s+/g, '.\n');
  const lines = processedText.split(/\r?\n/);
  let currentList = null;
  for (const line of lines) {
    const taskMatch = line.match(/^\s*[-*]\s*\[( |x|X)\]\s*(.*)$/);
    if (taskMatch) {
      if (!currentList) { currentList = document.createElement('ul'); wrapper.appendChild(currentList); }
      const li = document.createElement('li');
      const label = document.createElement('label');
      const checkbox = document.createElement('input');
      checkbox.type = 'checkbox';
      checkbox.disabled = true; // non-interactive for now
      checkbox.checked = !!taskMatch[1].trim();
      label.appendChild(checkbox);
      label.appendChild(document.createTextNode(' ' + taskMatch[2]));
      li.appendChild(label);
      currentList.appendChild(li);
    } else {
      if (currentList) currentList = null;
      const p = document.createElement('div');
      p.textContent = line;
      wrapper.appendChild(p);
    }
  }
  return wrapper;
}

async function loadModels(cli = state.currentCli || 'opencode') {
  try {
    state.currentCli = cli;
    if (el.cliSelect && el.cliSelect.value !== cli) el.cliSelect.value = cli;
    const data = await api(`/api/models?cli=${encodeURIComponent(cli)}`);
    state.models = data.models || [];
    el.modelSelect.innerHTML = '';
    state.models.forEach((m) => {
      const option = document.createElement('option');
      option.value = m.name || m.id || m;
      option.textContent = m.label || m.name || m.id || m;
      el.modelSelect.appendChild(option);
    });
    const customOpt = document.createElement('option');
    customOpt.value = 'custom';
    customOpt.textContent = 'Custom model...';
    el.modelSelect.appendChild(customOpt);
  } catch (error) { setStatus(`Model load failed: ${error.message}`); }
}

async function loadSessions() { 
  const data = await api('/api/sessions'); 
  state.sessions = data.sessions || []; 
  if (state.sessions.length && !state.currentCli) {
    state.currentCli = state.sessions[0].cli || 'opencode';
    if (el.cliSelect) el.cliSelect.value = state.currentCli;
  }
  renderSessions(); 
  if (!state.currentSessionId && state.sessions.length && !state.showingHome) {
    await selectSession(state.sessions[0].id); 
  }
} 

async function selectSession(id) { 
  state.currentSessionId = id; 
  const session = state.sessions.find((s) => s.id === id);
  if (session) {
    state.currentCli = session.cli || 'opencode';
    if (el.cliSelect) el.cliSelect.value = state.currentCli;
    await loadModels(state.currentCli);
  }
  state.showingHome = false;
  showChatView();
  renderSessions(); 
  await refreshCurrentSession(); 
  setPollingInterval(2500); 
}

function showHomeView() {
  state.showingHome = true;
  state.currentSessionId = null;
  el.homeView.style.display = 'block';
  el.chatArea.style.display = 'none';
  el.sessionMeta.style.display = 'none';
  document.querySelector('.composer').style.display = 'none';
  
  // Render all sessions in home view
  el.homeSessionList.innerHTML = '';
  state.sessions.forEach((session) => {
    const card = document.createElement('div');
    card.style.cssText = 'padding:16px; border:1px solid var(--border); border-radius:8px; cursor:pointer; transition:all 0.2s;';
    card.innerHTML = `
      <div style="font-weight:600; margin-bottom:8px;">${session.title || 'Chat'}</div>
      <div style="font-size:12px; color:var(--muted);">
        <span>Model: ${session.model}</span> • 
        <span>${session.messages.length} messages</span> • 
        <span>Updated: ${new Date(session.updatedAt).toLocaleString()}</span>
      </div>
    `;
    card.onmouseenter = () => card.style.borderColor = 'var(--accent)';
    card.onmouseleave = () => card.style.borderColor = 'var(--border)';
    card.onclick = () => selectSession(session.id);
    el.homeSessionList.appendChild(card);
  });
}

function showChatView() {
  state.showingHome = false;
  el.homeView.style.display = 'none';
  el.chatArea.style.display = 'block';
  el.sessionMeta.style.display = 'flex';
  document.querySelector('.composer').style.display = 'block';
}

// Set up SSE stream for a message
function streamMessage(sessionId, messageId) {
  // Close existing stream if any
  if (state.activeStreams.has(messageId)) {
    const existing = state.activeStreams.get(messageId);
    existing.close();
    state.activeStreams.delete(messageId);
  }
  
  const url = `/api/sessions/${sessionId}/messages/${messageId}/stream`;
  const eventSource = new EventSource(url);
  
  eventSource.onopen = () => {
    console.log('SSE stream opened for message', messageId);
  };
  
  eventSource.onmessage = (event) => {
    try {
      const data = JSON.parse(event.data);
      
      // Update the session with streaming data
      const session = state.sessions.find(s => s.id === sessionId);
      if (!session) return;
      
      const message = session.messages.find(m => m.id === messageId);
      if (!message) return;
      
      if (data.type === 'start') {
        message.status = 'running';
        setStatus('OpenCode is responding...');
      } else if (data.type === 'chunk') {
        // Update partial output immediately
        message.partialOutput = data.filtered || data.partialOutput || data.content;
        message.outputType = data.outputType;
        message.partialUpdatedAt = data.timestamp;
        message.status = 'running';
        
        // Re-render messages to show new content immediately
        renderMessages(session);
        setStatus('Streaming response...');
      } else if (data.type === 'complete') {
        message.reply = data.content;
        message.status = 'done';
        message.finishedAt = data.timestamp;
        message.outputType = data.outputType;
        message.opencodeExitCode = data.exitCode;
        eventSource.close();
        state.activeStreams.delete(messageId);
        renderMessages(session);
        setStatus('Complete');
        
        // Update session list
        renderSessions();
      } else if (data.type === 'error') {
        message.error = data.error;
        message.status = 'error';
        message.finishedAt = data.timestamp;
        message.opencodeExitCode = data.code;
        eventSource.close();
        state.activeStreams.delete(messageId);
        renderMessages(session);
        setStatus('Error: ' + data.error);
        
        // Update session list
        renderSessions();
      }
    } catch (err) {
      console.error('Failed to parse SSE message', err);
    }
  };
  
  eventSource.onerror = (err) => {
    console.error('SSE error', err);
    eventSource.close();
    state.activeStreams.delete(messageId);
    
    // Fall back to polling for this message
    setTimeout(() => refreshCurrentSession(), 1000);
  };
  
  state.activeStreams.set(messageId, eventSource);
}

async function refreshCurrentSession() {
  if (!state.currentSessionId) return;
  try {
    const { session } = await api(`/api/sessions/${state.currentSessionId}`);
    state.sessions = state.sessions.map((s) => (s.id === session.id ? session : s));
    renderSessions();
    renderSessionMeta(session);
    renderMessages(session);
    
    // Set up streaming for any running messages that don't have streams yet
    const running = (session.messages || []).filter((m) => m.status === 'running' || m.status === 'queued');
    running.forEach(msg => {
      if (!state.activeStreams.has(msg.id)) {
        streamMessage(session.id, msg.id);
      }
    });
    
    // Adjust polling - slower when using SSE
    if (running.length > 0) setPollingInterval(2000); 
    else setPollingInterval(5000);
  } catch (error) { setStatus(error.message); }
}

function setPollingInterval(intervalMs) {
  if (!intervalMs) return;
  if (state.pollingInterval === intervalMs) return;
  if (state.pollingTimer) clearInterval(state.pollingTimer);
  state.pollingInterval = intervalMs;
  state.pollingTimer = setInterval(refreshCurrentSession, state.pollingInterval);
}
async function createSession(options = {}) {
  const cli = el.cliSelect ? el.cliSelect.value : state.currentCli || 'opencode';
  state.currentCli = cli;
  const model = el.modelSelect.value || 'default';
  const payload = { model, cli };
  if (options.appId) payload.appId = options.appId;
  const { session } = await api('/api/sessions', { method: 'POST', body: JSON.stringify(payload) });
  state.sessions.unshift(session);
  renderSessions();
  await selectSession(session.id);
}

async function checkOpencodeStatus() {
  try {
    const status = await api('/api/opencode/status');
    state.opencodeStatus = status;
    
    if (!status.available) {
      setStatus(`Warning: OpenCode CLI not available - ${status.error || 'unknown error'}`);
    }
    
    return status;
  } catch (error) {
    console.error('Failed to check opencode status', error);
    return null;
  }
}

async function sendMessage() { 
  const content = el.messageInput.value.trim(); 
  if (!content) return; 
  
  // Create session if needed
  if (!state.currentSessionId) await createSession(); 
  const cli = el.cliSelect ? el.cliSelect.value : state.currentCli || 'opencode';
  state.currentCli = cli;
  
  let model = el.modelSelect.value; 
  if (model === 'custom') { 
    const txt = el.customModelInput.value.trim(); 
    if (txt) model = txt; 
    else { 
      setStatus('Please enter a custom model name'); 
      el.sendBtn.disabled = false; 
      return; 
    } 
  } 
  
  const mode = state.mode || 'agent';
  
  el.sendBtn.disabled = true; 
  setStatus('Sending...'); 
  try { 
    // Auto-generate title from first message if it's "New Chat"
    const session = state.sessions.find(s => s.id === state.currentSessionId);
    const isFirstMessage = session && session.title === 'New Chat' && session.messages.length === 0;
    
    const response = await api(`/api/sessions/${state.currentSessionId}/messages`, { 
      method: 'POST', 
      body: JSON.stringify({ content, model, mode, cli }), 
    }); 
    
    if (isFirstMessage) {
      const title = content.slice(0, 50) + (content.length > 50 ? '...' : '');
      await api(`/api/sessions/${state.currentSessionId}`, {
        method: 'PATCH',
        body: JSON.stringify({ title }),
      });
    }
    
    el.messageInput.value = ''; 
    
    // Start streaming immediately for the new message
    if (response.message && response.message.id) {
      streamMessage(state.currentSessionId, response.message.id);
    }
    
    await refreshCurrentSession(); 
  } catch (error) { 
    setStatus(error.message); 
  } finally { 
    el.sendBtn.disabled = false; 
  } 
}

function hookEvents() {
  el.newChat.addEventListener('click', () => {
    const currentSession = state.sessions.find(s => s.id === state.currentSessionId);
    const currentAppId = currentSession?.appId;
    createSession(currentAppId ? { appId: currentAppId } : {});
  });
  el.homeBtn.addEventListener('click', showHomeView);
  el.sendBtn.addEventListener('click', sendMessage);
  if (el.cliSelect) {
    el.cliSelect.addEventListener('change', async () => {
      state.currentCli = el.cliSelect.value;
      await loadModels(state.currentCli);
      if (state.currentSessionId) {
        try {
          await api(`/api/sessions/${state.currentSessionId}`, { method: 'PATCH', body: JSON.stringify({ cli: state.currentCli }) });
          await refreshCurrentSession();
        } catch (err) { setStatus(`Failed to update CLI: ${err.message}`); }
      }
    });
  }
  el.messageInput.addEventListener('keydown', (e) => { if (e.key === 'Enter' && (e.metaKey || e.ctrlKey)) sendMessage(); });
  // Support paste image handling: if user pastes an image, convert to base64 and send
  el.messageInput.addEventListener('paste', async (e) => {
    try {
      // Check clipboard items for an image
      const items = e.clipboardData && e.clipboardData.items ? Array.from(e.clipboardData.items) : [];
      const imageItem = items.find(it => it.type && it.type.startsWith('image/'));
      if (!imageItem) return; // no image in clipboard
      e.preventDefault();
      const blob = imageItem.getAsFile();
      if (!blob) return;
      const reader = new FileReader();
      reader.onload = async () => {
        const dataUrl = reader.result; // data:image/png;base64,...
        // Build a message with an attachment
        // Create session if needed
        if (!state.currentSessionId) await createSession();
        const cli = el.cliSelect ? el.cliSelect.value : state.currentCli || 'opencode';
        state.currentCli = cli;
        const model = el.modelSelect.value === 'custom' ? el.customModelInput.value.trim() || 'default' : el.modelSelect.value || 'default';
        const payload = { content: '', model, cli, mode: state.mode || 'agent', attachments: [{ name: blob.name || 'pasted-image', type: blob.type, data: dataUrl.split(',')[1] }] };
        setStatus('Uploading image...');
        el.sendBtn.disabled = true;
        try {
          const response = await api(`/api/sessions/${state.currentSessionId}/messages`, { method: 'POST', body: JSON.stringify(payload) });
          setStatus('Image sent');
          el.messageInput.value = '';
          
          // Start streaming for the new message
          if (response.message && response.message.id) {
            streamMessage(state.currentSessionId, response.message.id);
          }
          
          await refreshCurrentSession();
        } catch (err) { setStatus(`Failed to upload image: ${err.message}`); }
        el.sendBtn.disabled = false;
      };
      reader.readAsDataURL(blob);
    } catch (err) { console.error('Paste handler error', err); }
  });
  
  // Mode select handler
  el.modeSelect.addEventListener('change', () => {
    state.mode = el.modeSelect.value;
  });
  
  el.quickButtons.forEach((btn) => { btn.addEventListener('click', () => { const tag = btn.dataset.quick; const map = { shorter: 'Please condense the last answer.', more: 'Tell me more about this topic.', }; el.messageInput.value = map[tag] || ''; el.messageInput.focus(); }); });
  el.gitButtons.forEach((btn) => { btn.addEventListener('click', async () => {
    const action = btn.dataset.git;
    el.gitOutput.textContent = `Running ${action}...`;
    try {
      const payload = {};
      // Disable all git buttons while running
      el.gitButtons.forEach((b) => b.disabled = true);
      if (action === 'push' || action === 'sync') payload.message = (el.commitMessage && el.commitMessage.value) ? el.commitMessage.value : (el.modalCommitMessage && el.modalCommitMessage.value) || 'Update from web UI';
      const data = await api(`/api/git/${action}`, { method: 'POST', body: JSON.stringify(payload) });
      const out = data.output || data.stdout || data.stderr || 'Done';
      el.gitOutput.textContent = out;
    } catch (error) {
      // Show detailed output if available
      const lines = [];
      lines.push(error.message);
      if (error.stdout) lines.push('\nSTDOUT:\n' + error.stdout.trim());
      if (error.stderr) lines.push('\nSTDERR:\n' + error.stderr.trim());
      el.gitOutput.textContent = lines.join('\n');
    }
    // Re-enable the buttons
    el.gitButtons.forEach((b) => b.disabled = false);
  }); });

  // Hook up GitHub modal and its buttons
  if (el.githubButton) {
    el.githubButton.addEventListener('click', () => { 
      console.log('GitHub button clicked, showing modal');
      el.githubModal.style.display = 'flex'; 
    });
  } else {
    console.error('GitHub button element not found');
  }
  if (el.githubClose) {
    el.githubClose.addEventListener('click', () => { 
      console.log('GitHub close button clicked');
      el.githubModal.style.display = 'none'; 
    });
  }
  const modalButtons = document.querySelectorAll('#github-modal [data-git]');
  modalButtons.forEach((btn) => {
    btn.addEventListener('click', async () => {
      const action = btn.dataset.git;
      el.gitOutput.textContent = `Running ${action}...`;
      try {
        const payload = {};
        // Disable all git buttons while running
        el.gitButtons.forEach((b) => b.disabled = true);
        if (action === 'push' || action === 'sync') payload.message = el.modalCommitMessage && el.modalCommitMessage.value ? el.modalCommitMessage.value : 'Update from web UI';
        const data = await api(`/api/git/${action}`, { method: 'POST', body: JSON.stringify(payload) });
        const out = data.output || data.stdout || data.stderr || 'Done';
        el.gitOutput.textContent = out;
      } catch (error) {
        const lines = [];
        lines.push(error.message);
        if (error.stdout) lines.push('\nSTDOUT:\n' + error.stdout.trim());
        if (error.stderr) lines.push('\nSTDERR:\n' + error.stderr.trim());
        el.gitOutput.textContent = lines.join('\n');
      }
      el.gitButtons.forEach((b) => b.disabled = false);
    });
  });
  if (el.diagnosticsButton) {
    el.diagnosticsButton.addEventListener('click', async () => {
      el.gitOutput.textContent = 'Running diagnostics...';
      try {
        const data = await api('/api/diagnostics');
        const out = `Version:\n${data.version || ''}\n\nModels Output:\n${data.modelsOutput || ''}`;
        el.gitOutput.textContent = out;
      } catch (error) {
        el.gitOutput.textContent = `Diagnostics failed: ${error.message}`;
      }
    });
  }
  el.modelSelect.addEventListener('change', async () => {
    const selected = el.modelSelect.value;
    if (selected === 'custom') {
      el.customModelLabel.style.display = 'inline-flex';
      el.customModelInput.focus();
      return;
    }
    el.customModelLabel.style.display = 'none';
    // If a session is selected, update the session's active model on the server
    if (state.currentSessionId) {
      try {
        await api(`/api/sessions/${state.currentSessionId}`, { method: 'PATCH', body: JSON.stringify({ model: selected }) });
        await refreshCurrentSession();
      } catch (e) { setStatus(`Failed to update model: ${e.message}`); }
    }
  });
  el.customModelInput.addEventListener('keydown', async (e) => {
    if (e.key === 'Enter') {
      const txt = el.customModelInput.value.trim();
      if (!txt) return setStatus('Please enter a custom model name');
      if (state.currentSessionId) {
        try {
          await api(`/api/sessions/${state.currentSessionId}`, { method: 'PATCH', body: JSON.stringify({ model: txt }) });
          await refreshCurrentSession();
        } catch (err) { setStatus(`Failed to update custom model: ${err.message}`); }
      }
    }
  });
}

// Handle page visibility changes to maintain polling
document.addEventListener('visibilitychange', () => {
  const isVisible = document.visibilityState === 'visible';
  if (isVisible) {
    // User came back to the page, refresh immediately
    console.log('Page became visible, refreshing...');
    refreshCurrentSession().catch(err => console.error('Refresh failed', err));
    // Ensure polling interval is set
    if (!state.pollingTimer) {
      setPollingInterval(2500);
    }
  } else {
    // User left the page, but keep polling in the background at a slower rate
    console.log('Page became hidden, maintaining background polling...');
    if (state.pollingTimer) {
      setPollingInterval(5000); // Slower polling in background
    }
  }
});

// Handle page unload gracefully
window.addEventListener('beforeunload', (e) => {
  // Check if there are running processes
  const running = state.sessions.flatMap(s => s.messages || []).filter(m => m.status === 'running' || m.status === 'queued');
  if (running.length > 0) {
    console.log('Page unloading with running processes. They will continue on the server.');
    // Don't prevent unload, just log it
  }
});

// When user comes back to the page after a long time, ensure we reconnect to running processes
window.addEventListener('focus', () => {
  console.log('Window focused, checking for running processes to reconnect...');
  if (state.currentSessionId) {
    refreshCurrentSession().catch(err => console.error('Refresh on focus failed', err));
  }
});

(async function init() { 
  populateCliSelect(); 
  hookEvents(); 
  
  // Check opencode status on startup
  checkOpencodeStatus();
  
  await loadModels(state.currentCli); 
  await loadSessions(); 
  if (!state.sessions.length) await createSession(); 
  
  // Periodically check opencode status
  setInterval(checkOpencodeStatus, 30000);
  
  // Keep polling going even in background (for running processes)
  // Start with reasonable interval that will be adjusted by refreshCurrentSession
  setPollingInterval(5000);
})();
