// astroparse — annotator settings: model provider + API key, and the completion router

const AP_ANNOTATOR_KEY = 'astroparse_annotator_v1';

const AP_PROVIDERS = {
  builtin:   { label: 'Built-in (Claude)', needsKey: false, defaultModel: 'claude-haiku-4-5',
               hint: 'no key needed \u2014 runs on the prototype\u2019s built-in Claude' },
  anthropic: { label: 'Anthropic', needsKey: true, defaultModel: 'claude-haiku-4-5',
               keyPlaceholder: 'sk-ant-\u2026', hint: 'console.anthropic.com \u2192 API keys' },
  openai:    { label: 'OpenAI', needsKey: true, defaultModel: 'gpt-4o-mini',
               keyPlaceholder: 'sk-\u2026', hint: 'platform.openai.com \u2192 API keys' },
  gemini:    { label: 'Gemini', needsKey: true, defaultModel: 'gemini-2.0-flash',
               keyPlaceholder: 'AIza\u2026', hint: 'aistudio.google.com \u2192 Get API key' },
};

function apLoadAnnotator() {
  try {
    const raw = localStorage.getItem(AP_ANNOTATOR_KEY);
    if (raw) { const v = JSON.parse(raw); if (v && AP_PROVIDERS[v.provider]) return v; }
  } catch (e) {}
  return { provider: 'builtin', model: AP_PROVIDERS.builtin.defaultModel, key: '' };
}

function apSaveAnnotator(cfg) {
  try { localStorage.setItem(AP_ANNOTATOR_KEY, JSON.stringify(cfg)); } catch (e) {}
}

async function apComplete(cfg, prompt) {
  const provider = cfg.provider || 'builtin';
  const model = (cfg.model || AP_PROVIDERS[provider].defaultModel).trim();
  if (provider !== 'builtin' && !(cfg.key || '').trim()) {
    throw new Error('no API key set \u2014 open the annotator settings');
  }
  if (provider === 'builtin') {
    return await window.claude.complete(prompt);
  }
  if (provider === 'anthropic') {
    const res = await fetch('https://api.anthropic.com/v1/messages', {
      method: 'POST',
      headers: {
        'content-type': 'application/json',
        'x-api-key': cfg.key.trim(),
        'anthropic-version': '2023-06-01',
        'anthropic-dangerous-direct-browser-access': 'true',
      },
      body: JSON.stringify({ model: model, max_tokens: 400, messages: [{ role: 'user', content: prompt }] }),
    });
    if (!res.ok) throw new Error('Anthropic ' + res.status + ': ' + (await res.text()).slice(0, 140));
    const data = await res.json();
    return data.content[0].text;
  }
  if (provider === 'openai') {
    const res = await fetch('https://api.openai.com/v1/chat/completions', {
      method: 'POST',
      headers: { 'content-type': 'application/json', authorization: 'Bearer ' + cfg.key.trim() },
      body: JSON.stringify({ model: model, max_tokens: 400, messages: [{ role: 'user', content: prompt }] }),
    });
    if (!res.ok) throw new Error('OpenAI ' + res.status + ': ' + (await res.text()).slice(0, 140));
    const data = await res.json();
    return data.choices[0].message.content;
  }
  if (provider === 'gemini') {
    const url = 'https://generativelanguage.googleapis.com/v1beta/models/' + encodeURIComponent(model) +
      ':generateContent?key=' + encodeURIComponent(cfg.key.trim());
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'content-type': 'application/json' },
      body: JSON.stringify({ contents: [{ parts: [{ text: prompt }] }] }),
    });
    if (!res.ok) throw new Error('Gemini ' + res.status + ': ' + (await res.text()).slice(0, 140));
    const data = await res.json();
    return data.candidates[0].content.parts[0].text;
  }
  throw new Error('unknown provider');
}

function AnnotatorSettings({ cfg, onChange, onClose }) {
  const p = AP_PROVIDERS[cfg.provider];
  const set = (patch) => onChange({ ...cfg, ...patch });
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
  return (
    <div>
      <div className="ap-pop-backdrop" onClick={onClose}></div>
      <div className="ap-settings" data-screen-label="Annotator settings">
        <div className="ap-settings-title">The Annotator</div>
        <div className="ap-settings-sub">which mind writes in your margins</div>

        <div className="ap-field">
          <label className="ap-field-label">Provider</label>
          <div className="ap-provider-row">
            {Object.entries(AP_PROVIDERS).map(([id, pr]) => (
              <button
                key={id}
                className={'ap-provider' + (cfg.provider === id ? ' is-active' : '')}
                onClick={() => set({ provider: id, model: pr.defaultModel })}
              >{pr.label}</button>
            ))}
          </div>
        </div>

        <div className="ap-field">
          <label className="ap-field-label">Model</label>
          <input
            className="ap-input" type="text" value={cfg.model}
            onChange={(e) => set({ model: e.target.value })}
            spellCheck="false"
          />
        </div>

        {p.needsKey ? (
          <div className="ap-field">
            <label className="ap-field-label">API key</label>
            <input
              className="ap-input" type="password" value={cfg.key}
              placeholder={p.keyPlaceholder}
              onChange={(e) => set({ key: e.target.value })}
              spellCheck="false" autoComplete="off"
            />
            <div className="ap-field-hint">{p.hint} &middot; stored only in this browser, sent only to {p.label}</div>
          </div>
        ) : (
          <div className="ap-field-hint">{p.hint}</div>
        )}

        <div className="ap-settings-foot">
          <button className="ap-textbtn" onClick={onClose}>done</button>
        </div>
      </div>
    </div>
  );
}

Object.assign(window, { AnnotatorSettings, apComplete, apLoadAnnotator, apSaveAnnotator, AP_PROVIDERS });
