// ai-client.jsx — frontend wrapper that talks to the assistant proxy.
//
// One function: streamAssistant({ messages, personality, taskHint, onMeta,
// onDelta, onDone, onError, signal }). Posts to /api/assistant, reads the
// SSE stream, fires callbacks as events arrive.
//
// The proxy lives at http://localhost:3001 in dev. If you serve it from a
// different host or port, set window.CHRONO_API_BASE before this script
// runs, or pass `baseUrl` in the call.

const DEFAULT_BASE_URL = 'http://localhost:3001';

async function streamAssistant({
  messages,
  personality = 'concierge',
  taskHint = null,
  events = [],
  userContext = null,
  // NOTE: respect an empty-string base ('' = same origin). A plain `|| DEFAULT`
  // would wrongly fall back to localhost because '' is falsy.
  baseUrl = (typeof window !== 'undefined' && window.CHRONO_API_BASE != null) ? window.CHRONO_API_BASE : DEFAULT_BASE_URL,
  signal,
  onMeta,
  onDelta,
  onDone,
  onError,
}) {
  let response;
  try {
    const headers = { 'Content-Type': 'application/json', 'Accept': 'text/event-stream' };
    // Optional shared-secret for beta deployments. Set window.CHRONO_API_TOKEN
    // to authenticate against a proxy started with CHRONO_API_TOKEN set.
    const apiToken = typeof window !== 'undefined' && window.CHRONO_API_TOKEN;
    if (apiToken) headers['Authorization'] = `Bearer ${apiToken}`;
    response = await fetch(`${baseUrl}/api/assistant`, {
      method: 'POST',
      headers,
      body: JSON.stringify({ messages, personality, taskHint, events, userContext }),
      signal,
    });
  } catch (err) {
    onError && onError({ message: `Cannot reach assistant proxy at ${baseUrl}. Is the server running?`, cause: err });
    return;
  }

  if (!response.ok) {
    let detail = '';
    try { detail = (await response.json()).error || ''; } catch (_) {}
    onError && onError({ message: detail || `HTTP ${response.status}`, status: response.status });
    return;
  }

  const reader = response.body.getReader();
  const decoder = new TextDecoder();
  let buffer = '';
  let currentEvent = 'message';

  while (true) {
    let chunk;
    try {
      chunk = await reader.read();
    } catch (err) {
      onError && onError({ message: 'stream read failed', cause: err });
      return;
    }
    if (chunk.done) break;
    buffer += decoder.decode(chunk.value, { stream: true });

    // SSE frames are separated by a blank line.
    let frameEnd;
    while ((frameEnd = buffer.indexOf('\n\n')) !== -1) {
      const raw = buffer.slice(0, frameEnd);
      buffer = buffer.slice(frameEnd + 2);
      const lines = raw.split('\n');
      let evt = 'message';
      let data = '';
      for (const line of lines) {
        if (line.startsWith('event: ')) evt = line.slice(7).trim();
        else if (line.startsWith('data: ')) data += line.slice(6);
      }
      if (!data) continue;
      let payload;
      try { payload = JSON.parse(data); } catch (_) { continue; }

      if (evt === 'meta') onMeta && onMeta(payload);
      else if (evt === 'delta') onDelta && onDelta(payload);
      else if (evt === 'done') { onDone && onDone(payload); return; }
      else if (evt === 'error') { onError && onError(payload); return; }
    }
  }
}

// Convenience: classify intent from frontend without calling the server.
// Frontends can use this to set taskHint before sending (e.g. when the user
// triggers /plan from a button — we know it's complex without a heuristic).
function quickComplexity(text = '') {
  const lower = text.toLowerCase();
  if (/\b(week|month|reschedule everything|rearrange|reorganize|all my events|multiple events)\b/.test(lower)) return 'complex';
  return 'simple';
}

// Submit beta feedback (bug report or feature idea) to the proxy. Returns
// { ok: true } on success, or { ok: false, error } so the UI can show why.
async function submitFeedback({ type, message, email, meta } = {}) {
  const baseUrl = (typeof window !== 'undefined' && window.CHRONO_API_BASE != null) ? window.CHRONO_API_BASE : DEFAULT_BASE_URL;
  const headers = { 'Content-Type': 'application/json' };
  const apiToken = typeof window !== 'undefined' && window.CHRONO_API_TOKEN;
  if (apiToken) headers['Authorization'] = `Bearer ${apiToken}`;
  try {
    const res = await fetch(`${baseUrl}/api/feedback`, {
      method: 'POST',
      headers,
      body: JSON.stringify({ type, message, email, meta }),
    });
    if (!res.ok) {
      let detail = '';
      try { detail = (await res.json()).error || ''; } catch (_) {}
      return { ok: false, error: detail || `HTTP ${res.status}` };
    }
    return { ok: true };
  } catch (err) {
    return { ok: false, error: `Cannot reach the server at ${baseUrl}.` };
  }
}

Object.assign(window, { streamAssistant, quickComplexity, submitFeedback });
