// ============================================================================
// H33 Agent SDK — Public verification client (no auth needed)
// ============================================================================

import type { ProofResponse, AgentReceipt } from './types.js';

/**
 * Public verification client for H33 receipts. No API key is required --
 * anyone with a node ID or session ID can independently verify
 * cryptographic proofs.
 *
 * This is the "trust but verify" endpoint. Give it to auditors, regulators,
 * counterparties, or embed it in your own verification UI.
 *
 * @example
 * ```ts
 * const verifier = new H33Verifier();
 * const proof = await verifier.verify('node_abc123');
 * console.log(proof.valid); // true
 * ```
 */
export class H33Verifier {
  private readonly baseUrl: string;
  private readonly timeoutMs: number;

  /**
   * @param baseUrl   - API base URL. Defaults to https://api.h33.ai
   * @param timeoutMs - Request timeout in milliseconds. Defaults to 30000
   */
  constructor(baseUrl?: string, timeoutMs?: number) {
    this.baseUrl = (baseUrl || 'https://api.h33.ai').replace(/\/+$/, '');
    this.timeoutMs = timeoutMs ?? 30_000;
  }

  /**
   * Verify any receipt by its node ID. Returns the full proof including
   * the Merkle path and H33-74 attestation bytes.
   *
   * No API key is sent -- this is a public endpoint.
   *
   * @param nodeId - The node_id from an AgentReceipt
   * @returns Proof response with validity flag
   */
  async verify(nodeId: string): Promise<ProofResponse> {
    const url = `${this.baseUrl}/api/v1/agents/proof/${encodeURIComponent(nodeId)}`;

    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.timeoutMs);

    try {
      const res = await fetch(url, {
        method: 'GET',
        headers: { 'Accept': 'application/json' },
        signal: controller.signal,
      });

      if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new Error(
          `H33 verification failed: HTTP ${res.status} ${res.statusText}${text ? ` - ${text}` : ''}`
        );
      }

      return (await res.json()) as ProofResponse;
    } catch (err: unknown) {
      if (err instanceof Error && err.name === 'AbortError') {
        throw new Error(`H33 verification timed out after ${this.timeoutMs}ms for node ${nodeId}`);
      }
      throw err;
    } finally {
      clearTimeout(timer);
    }
  }

  /**
   * Verify that a session's entire chain is intact by replaying it and
   * checking each link.
   *
   * No API key is sent -- this is a public endpoint.
   *
   * @param sessionId - The session_id to verify
   * @returns Object with `intact` flag and `nodes` count
   */
  async verifyChain(sessionId: string): Promise<{ intact: boolean; nodes: number }> {
    const url = `${this.baseUrl}/api/v1/agents/proof/chain/${encodeURIComponent(sessionId)}`;

    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), this.timeoutMs);

    try {
      const res = await fetch(url, {
        method: 'GET',
        headers: { 'Accept': 'application/json' },
        signal: controller.signal,
      });

      if (!res.ok) {
        const text = await res.text().catch(() => '');
        throw new Error(
          `H33 chain verification failed: HTTP ${res.status} ${res.statusText}${text ? ` - ${text}` : ''}`
        );
      }

      return (await res.json()) as { intact: boolean; nodes: number };
    } catch (err: unknown) {
      if (err instanceof Error && err.name === 'AbortError') {
        throw new Error(
          `H33 chain verification timed out after ${this.timeoutMs}ms for session ${sessionId}`
        );
      }
      throw err;
    } finally {
      clearTimeout(timer);
    }
  }
}
