import { createHash } from "node:crypto";
import { logger } from "../util/logger.js";
/**
 * Calculates MD5 hash for a string
 */
function getMd5Hash(data) {
    return createHash("md5").update(data).digest("hex");
}
/**
 * Initiates an import of SQL into a Cloudflare D1 database.
 * Implements a flow to get an upload URL, upload the SQL file, and poll for status updates.
 *
 * Based on Cloudflare API:
 * https://developers.cloudflare.com/api/resources/d1/subresources/database/methods/import/
 *
 * @param api The CloudflareApi instance to use for requests
 * @param options Options including the database ID and SQL data to import
 * @returns An object containing the import results and status upon completion
 * @throws Will throw an error if the API call fails or the import process reports an error
 */
export async function importD1Database(api, options) {
    // Convert data to string for hashing if it's not already
    let sqlDataString;
    if (typeof options.sqlData === "string") {
        sqlDataString = options.sqlData;
    }
    else if (options.sqlData instanceof Blob) {
        sqlDataString = await options.sqlData.text();
    }
    else {
        // BufferSource (ArrayBuffer, etc.)
        sqlDataString = new TextDecoder().decode(options.sqlData);
    }
    // Calculate MD5 hash of SQL data
    const etag = getMd5Hash(sqlDataString);
    // Step 1: Initialize the import process to get an upload URL
    const initResponse = await api.post(`/accounts/${api.accountId}/d1/database/${options.databaseId}/import`, {
        action: "init",
        etag,
    });
    if (!initResponse.ok) {
        const errorData = (await initResponse.json());
        throw new Error(`Failed to initialize D1 database import: ${errorData.error || errorData.errors?.[0]?.message || "Unknown error"}`);
    }
    const initData = (await initResponse.json());
    const uploadResult = initData.result;
    if (!uploadResult.success || !uploadResult.upload_url) {
        throw new Error(uploadResult.error || "Failed to get upload URL for D1 import");
    }
    // Step 2: Upload the SQL file
    await uploadSqlFile(uploadResult.upload_url, options.sqlData, options.filename || uploadResult.filename);
    // Step 3: Ingest the uploaded file
    const ingestResponse = await api.post(`/accounts/${api.accountId}/d1/database/${options.databaseId}/import`, {
        action: "ingest",
        etag,
        filename: uploadResult.filename,
    });
    if (!ingestResponse.ok) {
        const errorData = (await ingestResponse.json());
        throw new Error(`Failed to ingest D1 database upload: ${errorData.error || errorData.errors?.[0]?.message || "Unknown error"}`);
    }
    const ingestData = (await ingestResponse.json());
    const ingestResult = ingestData.result;
    if (!ingestResult.success) {
        throw new Error(ingestResult.error || "Failed to start ingestion for D1 import");
    }
    if (!ingestResult.at_bookmark) {
        throw new Error("Ingest response did not contain a bookmark for polling");
    }
    // Step 4: Poll for status
    return pollImportStatus(api, options.databaseId, ingestResult.at_bookmark);
}
/**
 * Uploads an SQL file to the provided URL
 */
async function uploadSqlFile(uploadUrl, sqlData, filename) {
    // Convert data to the right format if needed
    let blob;
    if (typeof sqlData === "string") {
        blob = new Blob([sqlData], { type: "application/sql" });
    }
    else if (sqlData instanceof Blob) {
        blob = sqlData;
    }
    else {
        // BufferSource (ArrayBuffer, etc.)
        blob = new Blob([sqlData], { type: "application/sql" });
    }
    // Create a FormData object with the file
    const formData = new FormData();
    formData.append("file", blob, filename || "import.sql");
    const response = await fetch(uploadUrl, {
        method: "PUT",
        body: blob,
        headers: {
            "Content-Type": "application/sql",
        },
    });
    if (!response.ok) {
        throw new Error(`Failed to upload SQL file: ${response.statusText}`);
    }
}
/**
 * Polls for the import status with the provided bookmark
 */
async function pollImportStatus(api, databaseId, bookmark) {
    if (!bookmark) {
        throw new Error("Cannot poll an import without a bookmark");
    }
    const response = await api.post(`/accounts/${api.accountId}/d1/database/${databaseId}/import`, {
        action: "poll",
        current_bookmark: bookmark,
    });
    if (!response.ok) {
        const errorData = (await response.json());
        throw new Error(`Failed to poll D1 import status: ${errorData.error || errorData.errors?.[0]?.message || "Unknown error"}`);
    }
    const data = (await response.json()).result;
    if (!data.success) {
        throw new Error(data.error || "Unknown error during D1 import");
    }
    // Log messages for visibility
    if (data.messages && data.messages.length > 0) {
        for (const message of data.messages) {
            logger.log(`D1 Import: ${message}`);
        }
    }
    if (data.status === "complete" && data.result) {
        return {
            filename: data.filename || "import.sql",
            result: data.result,
            status: data.status,
            success: data.success,
        };
    }
    else if (data.status === "error") {
        throw new Error(data.error || "Error during D1 import");
    }
    else {
        // Continue polling with bookmark
        return pollImportStatus(api, databaseId, data.at_bookmark);
    }
}
//# sourceMappingURL=d1-import.js.map