import { mkdir, readFile, writeFile } from "node:fs/promises";
import path from "node:path";
import { bytesToHex, keccak256 } from "viem";
async function readJson(response) {
    const body = await response.text();
    let payload = {};
    try {
        payload = body ? JSON.parse(body) : {};
    }
    catch {
        throw new Error(body || `HTTP ${response.status}`);
    }
    if (!response.ok) {
        const error = typeof payload === "object" && payload && "error" in payload ? payload.error : undefined;
        throw new Error(typeof error === "string" ? error : `HTTP ${response.status}`);
    }
    return payload;
}
function apiUrl(config, pathname) {
    return new URL(pathname, config.apiUrl);
}
export class ProtocolApiClient {
    config;
    constructor(config) {
        this.config = config;
    }
    async marketplace() {
        const response = await fetch(apiUrl(this.config, "/api/protocol/marketplace"));
        return readJson(response);
    }
    async bounty(idOrCode) {
        const response = await fetch(apiUrl(this.config, `/api/protocol/sdk/bounties/${encodeURIComponent(idOrCode)}`));
        return readJson(response);
    }
    async downloadInstance(input) {
        const response = await fetch(new URL(input.instanceDownloadUrl, this.config.apiUrl));
        if (!response.ok) {
            throw new Error(`Instance download failed with HTTP ${response.status}.`);
        }
        const bytes = new Uint8Array(await response.arrayBuffer());
        const digest = keccak256(bytesToHex(bytes));
        if (digest.toLowerCase() !== input.expectedDigest.toLowerCase()) {
            throw new Error("Downloaded instance digest does not match the chain digest.");
        }
        await mkdir(this.config.artifactDir, { recursive: true });
        const filePath = path.join(this.config.artifactDir, `bounty-${input.bountyId}-instance.cnf`);
        await writeFile(filePath, bytes);
        return filePath;
    }
    async uploadSolution(filePath, fileName, input) {
        const bytes = await readFile(filePath);
        const form = new FormData();
        form.set("kind", "solution");
        if (input?.solutionKind !== undefined) {
            form.set("solutionKind", String(input.solutionKind));
        }
        if (input?.proofFormat !== undefined) {
            form.set("proofFormat", String(input.proofFormat));
        }
        form.set("file", new File([new Uint8Array(bytes)], fileName, { type: "application/x-dimacs-cnf" }));
        const response = await fetch(apiUrl(this.config, "/api/protocol/storage"), {
            method: "POST",
            body: form
        });
        return readJson(response);
    }
    async prepareCommit(input) {
        const response = await fetch(apiUrl(this.config, "/api/protocol/sdk/solver/prepare-commit"), {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(input)
        });
        return readJson(response);
    }
    async prepareReveal(input) {
        const response = await fetch(apiUrl(this.config, "/api/protocol/sdk/solver/prepare-reveal"), {
            method: "POST",
            headers: { "Content-Type": "application/json" },
            body: JSON.stringify(input)
        });
        return readJson(response);
    }
}
