/**
 * Diogenes Lightning L402 Client (Node.js / ESM)
 * Zero-dependency modern fetch client for executing Diogenes microservices
 * with automatic L402 macaroon & Lightning invoice settlement or demo preview.
 */

export class DiogenesL402Client {
  /**
   * @param {Object} options
   * @param {string} [options.gatewayUrl]
   * @param {string} [options.coinosToken]
   * @param {Function} [options.paymentHandler] - Async fn(invoice: string) => Promise<string> (returns preimage)
   * @param {boolean} [options.demoMode]
   */
  constructor(options = {}) {
    this.gatewayUrl = (options.gatewayUrl || "https://diogenes-micro-gateway.corinth.workers.dev").replace(/\/$/, "");
    this.coinosToken = options.coinosToken || null;
    this.paymentHandler = options.paymentHandler || null;
    this.demoMode = options.demoMode ?? false;
  }

  async _payViaCoinos(invoice) {
    if (!this.coinosToken) {
      throw new Error("No Coinos token configured for automated settlement.");
    }
    const res = await fetch("https://coinos.io/api/lightning/send", {
      method: "POST",
      headers: {
        "Content-Type": "application/json",
        Authorization: `Bearer ${this.coinosToken}`,
      },
      body: JSON.stringify({ invoice }),
    });
    const data = await res.json();
    const preimage = data.preimage || data.hash;
    if (!preimage) {
      throw new Error(`Coinos payment failed: ${JSON.stringify(data)}`);
    }
    return preimage;
  }

  _parseL402Header(authHeader = "") {
    const macaroon = authHeader.match(/macaroon="([^"]+)"/)?.[1] || "";
    const invoice = authHeader.match(/invoice="([^"]+)"/)?.[1] || "";
    return { macaroon, invoice };
  }

  /**
   * Call a Diogenes microservice with automatic L402 negotiation.
   * @param {string} endpoint - Path (e.g. '/api/v1/agent/guardrail-verify')
   * @param {Object} payload - JSON body parameters
   */
  async callMicroservice(endpoint, payload) {
    let url = `${this.gatewayUrl}${endpoint.startsWith("/") ? endpoint : "/" + endpoint}`;
    if (this.demoMode && !url.includes("?demo=true")) {
      url += "?demo=true";
    }

    const headers = {
      "Content-Type": "application/json",
      "User-Agent": "Diogenes-Node-L402/1.0",
    };

    let res = await fetch(url, {
      method: "POST",
      headers,
      body: JSON.stringify(payload),
    });

    if (res.status === 402 && !this.demoMode) {
      const authHeader = res.headers.get("www-authenticate") || "";
      let { macaroon, invoice } = this._parseL402Header(authHeader);

      if (!invoice) {
        const errJson = await res.json().catch(() => ({}));
        invoice = errJson.payment_request || errJson.invoice || "";
        macaroon = errJson.macaroon || "";
      }

      if (!invoice || !macaroon) {
        return { error: "L402_CHALLENGE_FAILED", message: "Missing macaroon or invoice in 402 challenge." };
      }

      let preimage;
      if (this.paymentHandler) {
        preimage = await this.paymentHandler(invoice);
      } else if (this.coinosToken) {
        preimage = await this._payViaCoinos(invoice);
      } else {
        return {
          error: "PAYMENT_REQUIRED",
          invoice,
          macaroon,
          notice: "Provide coinosToken, paymentHandler, or use demoMode: true",
        };
      }

      // Retry with L402 authorization
      res = await fetch(url, {
        method: "POST",
        headers: {
          ...headers,
          Authorization: `L402 ${macaroon}:${preimage}`,
        },
        body: JSON.stringify(payload),
      });
    }

    return await res.json();
  }
}
