// Neurvona REST client. Node.js 22+. No dependencies or automatic mutation retries.
export class NeurvonaError extends Error {
  constructor(status, error, retryAfter) {
    super(error?.message || `Neurvona returned HTTP ${status}`);
    this.name = 'NeurvonaError';
    this.status = status;
    this.code = error?.code || 'unexpected_response';
    this.retryAfterSeconds = retryAfter == null ? null : Number(retryAfter);
  }
}
export class Neurvona {
  constructor({apiKey = process.env.NEURVONA_API_KEY, baseUrl = 'https://neurvona.ai/api/v1'} = {}) {
    if (!apiKey) throw new Error('Set NEURVONA_API_KEY.');
    const url = new URL(baseUrl);
    if (url.protocol !== 'https:' && !['localhost', '127.0.0.1'].includes(url.hostname)) throw new Error('Use HTTPS.');
    this.apiKey = apiKey;
    this.baseUrl = baseUrl.replace(/\/$/, '');
  }
  async request(path, {method = 'GET', body, idempotencyKey} = {}) {
    const response = await fetch(this.baseUrl + path, {
      method, redirect: 'error', signal: AbortSignal.timeout(150_000),
      headers: {Authorization: `Bearer ${this.apiKey}`, ...(body !== undefined ? {'Content-Type': 'application/json'} : {}), ...(idempotencyKey ? {'Idempotency-Key': idempotencyKey} : {})},
      body: body === undefined ? undefined : JSON.stringify(body),
    });
    const data = await response.json();
    if (!response.ok) throw new NeurvonaError(response.status, data.error, response.headers.get('retry-after'));
    return data;
  }
  me() { return this.request('/me'); }
  // Persist a unique key per intended generation; reuse it after an ambiguous timeout.
  posts(input, idempotencyKey) {
    if (!idempotencyKey) throw new Error('Pass a stable idempotency key for this generation.');
    return this.request('/posts', {method: 'POST', body: input, idempotencyKey});
  }
  autopilot() { return this.request('/autopilot'); }
  updateAutopilot(settings) { return this.request('/autopilot', {method: 'PATCH', body: settings}); }
  pause() { return this.request('/autopilot/pause', {method: 'POST'}); }
  resume({consent}) { return this.request('/autopilot/resume', {method: 'POST', body: {consent}}); }
  activity(limit = 20) { return this.request('/activity?limit=' + encodeURIComponent(limit)); }
  boosts() { return this.request('/boosts'); }
  sources() { return this.request('/persona/sources'); }
  saveSource(source) { return this.request('/persona/sources', {method: 'POST', body: source}); }
  removeSource(id) { return this.request('/persona/sources?id=' + encodeURIComponent(id), {method: 'DELETE'}); }
  capabilities() { return this.request('/persona/capabilities'); }
  jobs() { return this.request('/persona/jobs'); }
  job(id) { return this.request('/persona/jobs/' + encodeURIComponent(id)); }
  startJob(input, idempotencyKey) {
    if (!idempotencyKey) throw new Error('Pass a stable idempotency key.');
    return this.request('/persona/jobs', {method: 'POST', body: input, idempotencyKey});
  }
  stopJob(id) { return this.request('/persona/jobs/' + encodeURIComponent(id), {method: 'DELETE'}); }
  connections() { return this.request('/persona/connections'); }
  updateConnection(provider, action) { return this.request('/persona/connections', {method: 'POST', body: {provider, action}}); }
  controlBoosts(input) { return this.request('/boosts', {method: 'POST', body: input}); }
  async transcribe(bytes, {contentType, title = 'Conversation', maxChargeCents, consent, idempotencyKey}) {
    if (!idempotencyKey || consent !== true) throw new Error('Approve the price and provide a stable idempotency key.');
    const query = new URLSearchParams({title, maxChargeCents: String(maxChargeCents), consent: 'true'});
    const r = await fetch(this.baseUrl + '/persona/transcriptions?' + query, {method: 'POST', redirect: 'error', signal: AbortSignal.timeout(150_000), headers: {Authorization: `Bearer ${this.apiKey}`, 'Content-Type': contentType, 'Idempotency-Key': idempotencyKey}, body: bytes});
    const data = await r.json();
    if (!r.ok) throw new NeurvonaError(r.status, data.error, r.headers.get('retry-after'));
    return data;
  }
  async recording(id) {
    const r = await fetch(this.baseUrl + '/persona/jobs/' + encodeURIComponent(id) + '/file', {redirect: 'error', signal: AbortSignal.timeout(60_000), headers: {Authorization: `Bearer ${this.apiKey}`}});
    if (!r.ok) throw new NeurvonaError(r.status, (await r.json()).error, r.headers.get('retry-after'));
    return r.arrayBuffer();
  }

}
