// Gemini API helpers — single key, used for audio transcription, vision, and text.
//
// API key is stored in localStorage under 'pepagent.geminiKey'.
// Set/clear it with the gear button in the header (see GeminiKeyButton).
//
// All three helpers below hit the v1beta generativelanguage endpoint.

const GEMINI_MODEL = 'gemini-2.5-flash';
const GEMINI_KEY_STORAGE = 'pepagent.geminiKey';

function getGeminiKey() {
  try { return localStorage.getItem(GEMINI_KEY_STORAGE) || ''; } catch (e) { return ''; }
}
function setGeminiKey(k) {
  try { localStorage.setItem(GEMINI_KEY_STORAGE, k || ''); } catch (e) {}
}

// Read a Blob/File as base64 (no data: prefix)
function blobToBase64(blob) {
  return new Promise((resolve, reject) => {
    const r = new FileReader();
    r.onload = () => {
      const s = String(r.result || '');
      const i = s.indexOf(',');
      resolve(i >= 0 ? s.slice(i + 1) : s);
    };
    r.onerror = () => reject(r.error || new Error('read failed'));
    r.readAsDataURL(blob);
  });
}

// Two paths:
//   1. User pasted their own key in the modal → call Google directly from the browser.
//   2. No user key → call /api/gemini (server proxy with GEMINI_API_KEY env var).
//
// The proxy is the default on the deployed site. The modal is a power-user override.
async function geminiCall(parts, opts = {}) {
  const { temperature = 0.7, maxOutputTokens = 1024, model, disableThinking = false } = opts;
  const userKey = getGeminiKey();
  const useModel = model || GEMINI_MODEL;

  const generationConfig = { temperature, maxOutputTokens };
  if (disableThinking) generationConfig.thinkingConfig = { thinkingBudget: 0 };

  if (userKey) {
    const url = `https://generativelanguage.googleapis.com/v1beta/models/${useModel}:generateContent?key=${encodeURIComponent(userKey)}`;
    const res = await fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({
        contents: [{ role: 'user', parts }],
        generationConfig,
      }),
    });
    if (!res.ok) {
      const errText = await res.text().catch(() => '');
      throw new Error(`Gemini ${res.status}: ${errText.slice(0, 200)}`);
    }
    const j = await res.json();
    const out = j?.candidates?.[0]?.content?.parts?.map((p) => p.text || '').join('').trim();
    if (!out) throw new Error('Gemini returned empty response');
    return out;
  }

  // Proxy path
  const res = await fetch('/api/gemini', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ parts, temperature, maxOutputTokens, model: useModel, disableThinking }),
  });
  if (!res.ok) {
    let detail = '';
    try { const j = await res.json(); detail = j.error || j.detail || ''; } catch (e) {}
    throw new Error(`Proxy ${res.status}: ${detail || 'request failed'}`);
  }
  const j = await res.json();
  if (!j.text) throw new Error('Proxy returned empty response');
  return j.text;
}

// Send audio (Blob from MediaRecorder) → text transcript.
//
// Notes:
// - Strip codec params from MIME (Gemini wants "audio/webm", not "audio/webm;codecs=opus").
// - Pad short audio with a low temp so the model doesn't refuse on greetings.
// - Don't use a sentinel like [unintelligible] — the model leaks it on edge cases.
async function geminiTranscribe(audioBlob) {
  const b64 = await blobToBase64(audioBlob);
  const rawMime = audioBlob.type || 'audio/webm';
  const mime = rawMime.split(';')[0].trim() || 'audio/webm';
  return geminiCall([
    { text: 'Transcribe the spoken words in this audio clip. Output ONLY the transcript text — nothing else, no quotes, no labels, no commentary, no explanations. If you hear no clear words at all, output a single space character.' },
    { inlineData: { mimeType: mime, data: b64 } },
  ], {
    temperature: 0.2,
    maxOutputTokens: 1024,
    disableThinking: true, // critical: 2.5-flash burns all tokens on thinking otherwise
  });
}

// Send an image + system context → analysis.
// The agent figures out whether it's a vial/box label, a body shot, or something else,
// and responds accordingly.
async function geminiAnalyzePeptidePhoto(imageBlob, { goal, profile, protocol } = {}) {
  const b64 = await blobToBase64(imageBlob);
  const mime = imageBlob.type || 'image/jpeg';

  const ctx = [];
  if (protocol) ctx.push(`Active protocol: ${protocol.label} (${protocol.stack.join(' + ')}, ${protocol.duration}).`);
  if (profile) ctx.push(`User: ${profile.weight}kg, ${profile.age}y, ${profile.experience}.`);
  const ctxLine = ctx.length ? '\n\nContext: ' + ctx.join(' ') : '';

  const prompt = `You are Pepagent, a peptide protocol advisor. Look at this photo and figure out what it is, then respond.

Possible subjects:
1. PEPTIDE VIAL / BOX / LABEL / RECONSTITUTION KIT — read the peptide name, dose, lot/batch, expiration, supplier if visible. Give: typical dosing for this peptide, mechanism in one sentence, half-life, common stack synergies, and any red flags you notice on the label (sketchy supplier wording, missing lot/batch, damaged seal, suspicious appearance of the powder/solution).
2. INJECTION SITE / BODY SHOT — comment on site rotation if visible, flag any concerning marks (significant redness, swelling, unusual bruising, lumps, infection signs), and remind about rotating sites every injection.
3. PROGRESS PHOTO (body composition / skin / hair) — give honest visual feedback against the user's stated goal, what to track over the cycle, and what a realistic timeline for visible change looks like.
4. SOMETHING ELSE — say briefly what you see and ask the user what they want to know.

Be conversational, 2-4 short paragraphs, no markdown, no bullet points, no headers. End with a one-line reminder that this is educational and to confirm with a clinician.${ctxLine}`;

  return geminiCall([
    { text: prompt },
    { inlineData: { mimeType: mime, data: b64 } },
  ], { temperature: 0.6, maxOutputTokens: 1024 });
}

// Plain text generation — used as a fallback / alternative to window.claude.complete.
async function geminiText(prompt) {
  return geminiCall([{ text: prompt }], { temperature: 0.7, maxOutputTokens: 1024 });
}

// Header gear button + modal to paste the key.
function GeminiKeyButton({ accent }) {
  const [open, setOpen] = React.useState(false);
  const [key, setKey] = React.useState(() => getGeminiKey());
  const hasKey = !!getGeminiKey();

  const save = () => { setGeminiKey(key.trim()); setOpen(false); };
  const clear = () => { setGeminiKey(''); setKey(''); setOpen(false); };

  return (
    <>
      <button
        className="gem-key-btn"
        onClick={() => setOpen(true)}
        title={hasKey ? 'Gemini key set — click to change' : 'Set Gemini API key'}
        style={{ '--accent': accent }}
      >
        <svg viewBox="0 0 24 24" width="14" height="14" fill="none" stroke="currentColor" strokeWidth="1.6">
          <circle cx="9" cy="14" r="4" />
          <path d="M12 11l8-8M16 7l3 3M18 5l3 3" strokeLinecap="round" />
        </svg>
        <span className={"gem-key-dot " + (hasKey ? 'on' : '')} style={{ background: hasKey ? accent : 'rgba(15,40,100,0.25)' }} />
      </button>

      {open && (
        <div className="gem-key-modal" onClick={(e) => { if (e.target === e.currentTarget) setOpen(false); }}>
          <div className="gem-key-card" style={{ '--accent': accent }}>
            <div className="gem-key-eyebrow">// API CONFIG</div>
            <div className="gem-key-title">Gemini API key</div>
            <div className="gem-key-sub">
              Used for voice transcription and photo analysis. Stored in your browser only — never sent anywhere except Google.
              <br />Get one at <span className="gem-key-link">aistudio.google.com/app/apikey</span>
            </div>
            <input
              type="password"
              className="gem-key-input"
              placeholder="AIza…"
              value={key}
              onChange={(e) => setKey(e.target.value)}
              autoFocus
            />
            <div className="gem-key-actions">
              {hasKey && <button className="ghost" onClick={clear}>CLEAR</button>}
              <button className="ghost" onClick={() => setOpen(false)}>CANCEL</button>
              <button className="cta" style={{ '--accent': accent }} onClick={save} disabled={!key.trim()}>
                SAVE
              </button>
            </div>
          </div>
        </div>
      )}
    </>
  );
}

window.geminiTranscribe = geminiTranscribe;
window.geminiAnalyzePeptidePhoto = geminiAnalyzePeptidePhoto;
window.geminiText = geminiText;
window.getGeminiKey = getGeminiKey;
window.GeminiKeyButton = GeminiKeyButton;
