import { BondsModuleV3 }      from "./bonds";
import { MandateModuleV3 }    from "./mandate";
import { RewardModuleV3 }     from "./rewards";
import { TasksModuleV3 }      from "./tasks";
import { ReputationModuleV3 } from "./reputation";
import { X402ClientV3 }       from "./x402";
import { assertV3Envelope, type V3Envelope } from "../../compat/v3-envelope";
import type { VaultfireV3Config } from "./types";

export class VaultfireSDKv3 {
  readonly config: VaultfireV3Config;
  readonly bonds: BondsModuleV3;
  readonly mandate: MandateModuleV3;
  readonly rewards: RewardModuleV3;
  readonly tasks: TasksModuleV3;
  readonly reputation: ReputationModuleV3;
  readonly x402: X402ClientV3;

  constructor(cfg: VaultfireV3Config) {
    this.config = cfg;
    this.bonds = new BondsModuleV3(cfg);
    this.mandate = new MandateModuleV3(cfg);
    this.rewards = new RewardModuleV3(cfg);
    this.tasks = new TasksModuleV3(cfg);
    this.reputation = new ReputationModuleV3(cfg);
    this.x402 = new X402ClientV3(cfg);
  }

  /** True when V3 is paused. Throws when authoritative status is unavailable. */
  async pauseGate(): Promise<boolean> {
    let response: Response;
    try {
      response = await fetch(`${this.config.baseUrl}/api/v3/protocol/status`);
    } catch (error) {
      throw new V3WritesBlockedError("V3 status request failed", { cause: error });
    }
    const status: unknown = await response.json().catch(() => null);
    if (!response.ok || !isHealthyStatus(status)) {
      throw new V3WritesBlockedError("V3 status is unavailable or degraded");
    }
    return status.data.v3.pausedContracts.length > 0;
  }
}

type HealthyStatus = V3Envelope<{ v3: { pausedContracts: string[] } }> & { status: "ok"; data: { v3: { pausedContracts: string[] } } };

function isHealthyStatus(value: unknown): value is HealthyStatus {
  try {
    assertV3Envelope(value);
  } catch {
    return false;
  }
  const candidate = value as V3Envelope<unknown>;
  return (
    candidate.status === "ok" &&
    !!candidate.data &&
    typeof candidate.data === "object" &&
    "v3" in candidate.data &&
    !!candidate.data.v3 &&
    typeof candidate.data.v3 === "object" &&
    "pausedContracts" in candidate.data.v3 &&
    Array.isArray(candidate.data.v3.pausedContracts)
  );
}

export class V3WritesBlockedError extends Error {
  constructor(message: string, options?: ErrorOptions) {
    super(message, options);
    this.name = "V3WritesBlockedError";
  }
}

export function createVaultfireSDKv3(cfg: VaultfireV3Config) {
  return new VaultfireSDKv3(cfg);
}
