<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Local RAG Chat</title>
  <style>
    * { box-sizing: border-box; }
    body {
      font-family: "SF Mono", "Consolas", "Monaco", monospace;
      margin: 0;
      height: 100vh;
      overflow: hidden;
      background: #0f0f12;
      color: #e4e4e7;
      display: flex;
      flex-direction: column;
    }
    header {
      flex-shrink: 0;
      padding: 1rem 1.5rem;
      border-bottom: 1px solid #27272a;
      background: #18181b;
    }
    header h1 {
      margin: 0;
      font-size: 1rem;
      font-weight: 600;
      letter-spacing: 0.02em;
    }
    header p {
      margin: 0.25rem 0 0;
      font-size: 0.75rem;
      color: #71717a;
    }
    #messages {
      flex: 1;
      min-height: 0;
      overflow-y: auto;
      padding: 1.5rem;
      display: flex;
      flex-direction: column;
      gap: 1rem;
    }
    .msg {
      max-width: 85%;
      padding: 0.75rem 1rem;
      border-radius: 8px;
      font-size: 0.9rem;
      line-height: 1.5;
      word-break: break-word;
    }
    .msg.user, .msg.error {
      white-space: pre-wrap;
    }
    .msg.assistant .markdown-body {
      white-space: normal;
    }
    .msg.assistant .markdown-body h1, .msg.assistant .markdown-body h2, .msg.assistant .markdown-body h3 {
      margin: 0.75em 0 0.35em;
      font-size: 1em;
      font-weight: 600;
    }
    .msg.assistant .markdown-body h1:first-child, .msg.assistant .markdown-body h2:first-child, .msg.assistant .markdown-body h3:first-child { margin-top: 0; }
    .msg.assistant .markdown-body p { margin: 0.5em 0; }
    .msg.assistant .markdown-body p:first-child { margin-top: 0; }
    .msg.assistant .markdown-body p:last-child { margin-bottom: 0; }
    .msg.assistant .markdown-body pre {
      margin: 0.5em 0;
      padding: 0.6rem;
      background: #18181b;
      border-radius: 6px;
      overflow-x: auto;
      font-size: 0.85em;
    }
    .msg.assistant .markdown-body code {
      background: #18181b;
      padding: 0.15em 0.35em;
      border-radius: 4px;
      font-size: 0.9em;
    }
    .msg.assistant .markdown-body pre code {
      padding: 0;
      background: none;
    }
    .msg.assistant .markdown-body ul, .msg.assistant .markdown-body ol { margin: 0.5em 0; padding-left: 1.4em; }
    .msg.assistant .markdown-body li { margin: 0.25em 0; }
    .msg.assistant .markdown-body a { color: #60a5fa; text-decoration: none; }
    .msg.assistant .markdown-body a:hover { text-decoration: underline; }
    .msg.user {
      align-self: flex-end;
      background: #3f3f46;
      color: #fafafa;
    }
    .msg.assistant {
      align-self: flex-start;
      background: #27272a;
      border: 1px solid #3f3f46;
    }
    .msg.error {
      background: #451a1a;
      border: 1px solid #7f1d1d;
      color: #fecaca;
    }
    .msg .label {
      font-size: 0.7rem;
      text-transform: uppercase;
      letter-spacing: 0.05em;
      color: #71717a;
      margin-bottom: 0.5rem;
      display: block;
    }
    #input-area {
      flex-shrink: 0;
      padding: 1rem 1.5rem 1.5rem;
      border-top: 1px solid #27272a;
      background: #18181b;
    }
    #provider-row {
      display: flex;
      align-items: center;
      gap: 0.5rem;
      margin-bottom: 0.5rem;
      font-size: 0.8rem;
      color: #71717a;
    }
    #provider-row label { flex-shrink: 0; }
    #provider {
      padding: 0.25rem 0.5rem;
      font: inherit;
      font-size: 0.85rem;
      color: #e4e4e7;
      background: #27272a;
      border: 1px solid #3f3f46;
      border-radius: 6px;
    }
    #input-row {
      display: flex;
      gap: 0.5rem;
      align-items: flex-end;
    }
    #input {
      flex: 1;
      min-height: 44px;
      height: 44px;
      max-height: 160px;
      padding: 0.6rem 1rem;
      font: inherit;
      font-size: 0.9rem;
      color: #e4e4e7;
      background: #27272a;
      border: 1px solid #3f3f46;
      border-radius: 8px;
      resize: none;
      outline: none;
    }
    #input::placeholder { color: #71717a; }
    #input:focus { border-color: #52525b; }
    #send {
      height: 44px;
      padding: 0 1.2rem;
      font: inherit;
      font-size: 0.85rem;
      font-weight: 500;
      color: #0f0f12;
      background: #e4e4e7;
      border: none;
      border-radius: 8px;
      cursor: pointer;
    }
    #send:hover { background: #fafafa; }
    #send:disabled {
      opacity: 0.5;
      cursor: not-allowed;
    }
    .loading {
      align-self: flex-start;
      padding: 0.5rem 1rem;
      font-size: 0.8rem;
      color: #71717a;
    }
  </style>
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
  <script src="https://cdn.jsdelivr.net/npm/dompurify/dist/purify.min.js"></script>
</head>
<body>
  <header>
    <h1>RAG Chat</h1>
    <p>Ask questions about your documents. Answers are generated from a local vector store + Ollama / OpenAI.</p>
  </header>

  <div id="messages"></div>

  <div id="input-area">
    <div id="provider-row">
      <label for="provider">LLM provider:</label>
      <select id="provider">
        <option value="ollama">Ollama</option>
        <option value="openai">OpenAI</option>
      </select>
    </div>
    <div id="input-row">
      <textarea id="input" rows="1" placeholder="Ask a question…" autofocus></textarea>
      <button type="button" id="send">Send</button>
    </div>
  </div>

  <script>
    const messagesEl = document.getElementById('messages');
    const inputEl = document.getElementById('input');
    const sendBtn = document.getElementById('send');
    const providerEl = document.getElementById('provider');
    const chatHistory = [];

    (async function initProviders() {
      try {
        const res = await fetch('/api/providers');
        const data = await res.json();
        if (!data.openai) {
          const opt = providerEl.querySelector('option[value="openai"]');
          opt.disabled = true;
          opt.textContent = 'OpenAI (not configured)';
          if (providerEl.value === 'openai') providerEl.value = 'ollama';
        }
      } catch (_) {}
    })();

    function appendMessage(role, text, isError = false, llmProvider = null) {
      text = text ?? '';
      const div = document.createElement('div');
      div.className = 'msg ' + (isError ? 'error' : role);
      let label = role === 'user' ? 'You' : (llmProvider === 'openai' ? 'ChatGPT + RAG' : 'Ollama + RAG');
      let body;
      if (role === 'assistant' && !isError) {
        const rawHtml = marked.parse(text, { gfm: true, breaks: true });
        body = '<div class="markdown-body">' + DOMPurify.sanitize(rawHtml) + '</div>';
      } else {
        body = escapeHtml(text);
      }
      div.innerHTML = '<span class="label">' + label + '</span>' + body;
      messagesEl.appendChild(div);
      messagesEl.scrollTop = messagesEl.scrollHeight;
      chatHistory.push({ role: role, content: text });
    }

    function escapeHtml(s) {
      const div = document.createElement('div');
      div.textContent = s;
      return div.innerHTML;
    }

    function setLoading(show) {
      if (show) {
        const el = document.createElement('div');
        el.className = 'loading';
        el.id = 'loading-dot';
        el.textContent = 'Thinking…';
        messagesEl.appendChild(el);
        messagesEl.scrollTop = messagesEl.scrollHeight;
      } else {
        const el = document.getElementById('loading-dot');
        if (el) el.remove();
      }
      sendBtn.disabled = show;
    }

    async function send() {
      const text = inputEl.value.trim();
      if (!text) return;
      inputEl.value = '';
      appendMessage('user', text);

      setLoading(true);
      try {
        const history = chatHistory.slice(0, -1);
        const res = await fetch('/api/chat', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            message: text,
            history: history,
            llm_provider: providerEl.value
          })
        });
        const data = await res.json();
        setLoading(false);
        if (data.retrieved && data.retrieved.length > 0) {
          console.groupCollapsed('[RAG] Retrieved ' + data.retrieved.length + ' chunk(s)');
          data.retrieved.forEach(function(chunk, i) {
            console.group('Chunk ' + (i + 1) + ' | ' + (chunk.source || '') + (chunk.page != null ? ' p.' + chunk.page : ''));
            console.log(chunk.content);
            console.groupEnd();
          });
          console.groupEnd();
        }
        if (data.error) {
          appendMessage('assistant', data.error, true, providerEl.value);
        } else {
          appendMessage('assistant', (data.answer || '(No response)').trim(), false, providerEl.value);
        }
      } catch (err) {
        setLoading(false);
        appendMessage('assistant', 'Request failed: ' + err.message, true);
      }
    }

    sendBtn.addEventListener('click', send);
    inputEl.addEventListener('keydown', (e) => {
      if (e.key === 'Enter' && !e.shiftKey) {
        e.preventDefault();
        send();
      }
    });
  </script>
</body>
</html>
