/* Lojiq Public API — thin TypeScript client, generated from openapi.yaml 1.2.0.
 * Zero dependencies (global fetch; Node 18+, Deno, Bun, browsers with a server-side proxy).
 * One method per operation. Bodies and responses are loosely typed; see https://docs.lojiq.ai/reference/ for fields.
 * NOT an openapi-generator build — run tools/generate-sdks.sh for typed models. */

export type Json = Record<string, unknown>;
export interface LojiqOptions { apiKey: string; baseUrl?: string; fetch?: typeof fetch; userAgent?: string; }
export interface Page<T = Json> { data: T[]; limit: number; offset: number; }

export class LojiqError extends Error {
  constructor(public status: number, public code: string, public body: unknown, public requestId: string | null, message?: string) {
    super(message || `${status} ${code}`);
    this.name = 'LojiqError';
  }
}

export class Lojiq {
  private baseUrl: string; private apiKey: string; private f: typeof fetch; private ua: string;
  constructor(opts: LojiqOptions) {
    if (!opts?.apiKey) throw new Error('Lojiq: apiKey is required');
    this.apiKey = opts.apiKey; this.baseUrl = (opts.baseUrl || 'https://api.lojiq.ai/v1').replace(/\/+$/, '');
    this.f = opts.fetch || globalThis.fetch; this.ua = opts.userAgent || 'lojiq-ts/1.2.0';
  }

  /** Low-level request. kind: json | text | bytes | redirect (returns the Location header). */
  async request<T = unknown>(method: string, path: string, opts: { query?: Record<string, unknown>; body?: unknown; kind?: 'json' | 'text' | 'bytes' | 'redirect'; auth?: boolean } = {}): Promise<T> {
    const url = new URL(this.baseUrl + path);
    for (const [k, v] of Object.entries(opts.query || {})) if (v !== undefined && v !== null) url.searchParams.set(k, String(v));
    const headers: Record<string, string> = { 'Accept': 'application/json', 'User-Agent': this.ua };
    if (opts.auth !== false) headers['Authorization'] = `Bearer ${this.apiKey}`;
    if (opts.body !== undefined) headers['Content-Type'] = 'application/json';
    const res = await this.f(url, { method, headers, body: opts.body !== undefined ? JSON.stringify(opts.body) : undefined, redirect: opts.kind === 'redirect' ? 'manual' : 'follow' });
    const requestId = res.headers.get('x-request-id');
    if (opts.kind === 'redirect') {
      if (res.status >= 300 && res.status < 400) return (res.headers.get('location') as unknown) as T;
    }
    if (!res.ok) {
      let body: unknown = null; let code = `http_${res.status}`; let msg: string | undefined;
      try { body = await res.json(); code = (body as Json)?.error as string || code; msg = (body as Json)?.message as string | undefined; } catch { /* non-JSON error */ }
      throw new LojiqError(res.status, code, body, requestId, msg ? `${res.status} ${code}: ${msg}` : undefined);
    }
    if (opts.kind === 'text') return (await res.text()) as unknown as T;
    if (opts.kind === 'bytes') return (await res.arrayBuffer()) as unknown as T;
    return (await res.json()) as T;
  }
  /** API metadata — GET / (scope: none) */
  getApiMeta<T = Json>(): Promise<T> { return this.request<T>('GET', `/`); }
  /** List webhook event types — GET /event-catalog (scope: webhooks:manage) */
  listEventCatalog<T = Json>(): Promise<T> { return this.request<T>('GET', `/event-catalog`); }
  /** Get your organization — GET /account (scope: account:read) */
  getAccount<T = Json>(): Promise<T> { return this.request<T>('GET', `/account`); }
  /** List leads — GET /leads (scope: leads:read) */
  listLeads<T = Json>(query: { limit?: number; offset?: number; campaign_id?: string; phone_number?: string; status?: string } = {}): Promise<T> { return this.request<T>('GET', `/leads`, { query }); }
  /** Create a lead — POST /leads (scope: leads:write) */
  createLead<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/leads`, { body }); }
  /** Get a lead — GET /leads/{id} (scope: leads:read) */
  getLead<T = Json>(id: string): Promise<T> { return this.request<T>('GET', `/leads/${encodeURIComponent(String(id))}`); }
  /** Update a lead — PATCH /leads/{id} (scope: leads:write) */
  updateLead<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('PATCH', `/leads/${encodeURIComponent(String(id))}`, { body }); }
  /** Bulk import leads from CSV — POST /leads/bulk (scope: leads:write) */
  bulkImportLeads<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/leads/bulk`, { body }); }
  /** Preflight a CSV — POST /leads/inspect-csv (scope: leads:write) */
  inspectLeadsCsv<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/leads/inspect-csv`, { body }); }
  /** Export leads as CSV — GET /leads.csv (scope: leads:read) */
  exportLeadsCsv(query: { campaign_id?: string } = {}): Promise<string> { return this.request('GET', `/leads.csv`, { query, kind: 'text' }); }
  /** List contacts — GET /contacts (scope: contacts:read) — NOT YET AVAILABLE on production */
  listContacts<T = Json>(query: { limit?: number; offset?: number } = {}): Promise<T> { return this.request<T>('GET', `/contacts`, { query }); }
  /** Create a contact — POST /contacts (scope: contacts:write) — NOT YET AVAILABLE on production */
  createContact<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/contacts`, { body }); }
  /** List campaigns — GET /campaigns (scope: campaigns:read) */
  listCampaigns<T = Json>(query: { limit?: number; offset?: number; status?: string } = {}): Promise<T> { return this.request<T>('GET', `/campaigns`, { query }); }
  /** Get a campaign — GET /campaigns/{id} (scope: campaigns:read) */
  getCampaign<T = Json>(id: string): Promise<T> { return this.request<T>('GET', `/campaigns/${encodeURIComponent(String(id))}`); }
  /** Start (or resume) a campaign — POST /campaigns/{id}/start (scope: campaigns:write) */
  startCampaign<T = Json>(id: string): Promise<T> { return this.request<T>('POST', `/campaigns/${encodeURIComponent(String(id))}/start`); }
  /** Pause a campaign — POST /campaigns/{id}/stop (scope: campaigns:write) */
  stopCampaign<T = Json>(id: string): Promise<T> { return this.request<T>('POST', `/campaigns/${encodeURIComponent(String(id))}/stop`); }
  /** List calls — GET /calls (scope: calls:read) */
  listCalls<T = Json>(query: { limit?: number; offset?: number; campaign_id?: string; lead_id?: string } = {}): Promise<T> { return this.request<T>('GET', `/calls`, { query }); }
  /** Start an ad-hoc call — POST /calls (scope: calls:write) */
  createCall<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/calls`, { body }); }
  /** Get a call — GET /calls/{id} (scope: calls:read) */
  getCall<T = Json>(id: string): Promise<T> { return this.request<T>('GET', `/calls/${encodeURIComponent(String(id))}`); }
  /** Get a call transcript — GET /calls/{id}/transcript (scope: calls:read) */
  getCallTranscript<T = Json>(id: string): Promise<T> { return this.request<T>('GET', `/calls/${encodeURIComponent(String(id))}/transcript`); }
  /** End a live call — POST /calls/{id}/hangup (scope: calls:write) */
  hangupCall<T = Json>(id: string): Promise<T> { return this.request<T>('POST', `/calls/${encodeURIComponent(String(id))}/hangup`); }
  /** Get a call recording — GET /calls/{id}/recording (scope: calls:read) */
  getCallRecording(id: string): Promise<string> { return this.request('GET', `/calls/${encodeURIComponent(String(id))}/recording`, { kind: 'redirect' }); }
  /** List voice agents — GET /agents (scope: agents:read) */
  listAgents<T = Json>(query: { limit?: number; offset?: number; created_via?: string } = {}): Promise<T> { return this.request<T>('GET', `/agents`, { query }); }
  /** Create a voice agent — POST /agents (scope: agents:write) */
  createAgent<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/agents`, { body }); }
  /** Get a voice agent — GET /agents/{id} (scope: agents:read) */
  getAgent<T = Json>(id: string): Promise<T> { return this.request<T>('GET', `/agents/${encodeURIComponent(String(id))}`); }
  /** Update a voice agent — PATCH /agents/{id} (scope: agents:write) */
  updateAgent<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('PATCH', `/agents/${encodeURIComponent(String(id))}`, { body }); }
  /** Delete a voice agent — DELETE /agents/{id} (scope: agents:write) */
  deleteAgent<T = Json>(id: string): Promise<T> { return this.request<T>('DELETE', `/agents/${encodeURIComponent(String(id))}`); }
  /** Assign an inbound number — POST /agents/{id}/phone-number (scope: agents:write) */
  assignAgentPhoneNumber<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('POST', `/agents/${encodeURIComponent(String(id))}/phone-number`, { body }); }
  /** Unassign the inbound number — DELETE /agents/{id}/phone-number (scope: agents:write) */
  unassignAgentPhoneNumber<T = Json>(id: string): Promise<T> { return this.request<T>('DELETE', `/agents/${encodeURIComponent(String(id))}/phone-number`); }
  /** List an agent's calls — GET /agents/{id}/calls (scope: calls:read) */
  listAgentCalls<T = Json>(id: string, query: { limit?: number; offset?: number } = {}): Promise<T> { return this.request<T>('GET', `/agents/${encodeURIComponent(String(id))}/calls`, { query }); }
  /** Start a call with an agent — POST /agents/{id}/calls (scope: calls:write) */
  createAgentCall<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('POST', `/agents/${encodeURIComponent(String(id))}/calls`, { body }); }
  /** List voices — GET /voices (scope: voices:read) */
  listVoices<T = Json>(): Promise<T> { return this.request<T>('GET', `/voices`); }
  /** Preview a voice — GET /voices/{id}/preview (scope: voices:read) */
  previewVoice(id: string): Promise<ArrayBuffer> { return this.request('GET', `/voices/${encodeURIComponent(String(id))}/preview`, { kind: 'bytes' }); }
  /** List appointments — GET /appointments (scope: appointments:read) */
  listAppointments<T = Json>(query: { limit?: number; offset?: number; status?: string; lead_id?: string } = {}): Promise<T> { return this.request<T>('GET', `/appointments`, { query }); }
  /** Cancel an appointment — POST /appointments/{id}/cancel (scope: appointments:write) */
  cancelAppointment<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('POST', `/appointments/${encodeURIComponent(String(id))}/cancel`, { body }); }
  /** List deals — GET /deals (scope: deals:read) — NOT YET AVAILABLE on production */
  listDeals<T = Json>(query: { limit?: number; offset?: number } = {}): Promise<T> { return this.request<T>('GET', `/deals`, { query }); }
  /** Update a deal — PATCH /deals/{id} (scope: deals:write) — NOT YET AVAILABLE on production */
  updateDeal<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('PATCH', `/deals/${encodeURIComponent(String(id))}`, { body }); }
  /** List webhook subscriptions — GET /webhooks (scope: webhooks:manage) */
  listWebhooks<T = Json>(): Promise<T> { return this.request<T>('GET', `/webhooks`); }
  /** Create a webhook subscription — POST /webhooks (scope: webhooks:manage) */
  createWebhook<T = Json>(body: Json): Promise<T> { return this.request<T>('POST', `/webhooks`, { body }); }
  /** Update a webhook subscription — PATCH /webhooks/{id} (scope: webhooks:manage) */
  updateWebhook<T = Json>(id: string, body: Json): Promise<T> { return this.request<T>('PATCH', `/webhooks/${encodeURIComponent(String(id))}`, { body }); }
  /** Delete a webhook subscription — DELETE /webhooks/{id} (scope: webhooks:manage) */
  deleteWebhook<T = Json>(id: string): Promise<T> { return this.request<T>('DELETE', `/webhooks/${encodeURIComponent(String(id))}`); }
  /** OpenAPI spec (YAML) — GET /openapi.yaml (scope: none) */
  getOpenApiSpec(): Promise<string> { return this.request('GET', `/openapi.yaml`, { kind: 'text', auth: false }); }
  /** Getting-started guide (Markdown) — GET /getting-started.md (scope: none) */
  getGettingStarted(): Promise<string> { return this.request('GET', `/getting-started.md`, { kind: 'text', auth: false }); }
  /** Browser voice SDK (ES module) — GET /sdk/voice.js (scope: none) */
  getVoiceSdk(): Promise<string> { return this.request('GET', `/sdk/voice.js`, { kind: 'text', auth: false }); }
  /** Built-in reference page — GET /docs (scope: none) */
  getRedocPage(): Promise<string> { return this.request('GET', `/docs`, { kind: 'text', auth: false }); }
}

export default Lojiq;
