import * as yaml from "yaml";
import { Resource } from "../resource.js";
import { CloudflareApiError, handleApiError } from "./api-error.js";
import { createCloudflareApi, } from "./api.js";
import { findZoneForHostname } from "./zone.js";
/**
 * Cloudflare API Gateway Schema manages OpenAPI v3 schemas for API validation.
 *
 * @example
 * ## Basic schema upload with inline YAML
 *
 * const apiSchema = await APISchema("my-api-schema", {
 *   zone: myZone,
 *   name: "my-api-v1"
 *   schema: `
 *     openapi: 3.0.0
 *     info:
 *       title: My API
 *       version: 1.0.0
 *     servers:
 *       - url: https://api.example.com
 *     paths:
 *       /users:
 *         get:
 *           operationId: getUsers
 *           responses:
 *             '200':
 *               description: Success
 *   `,
 * });
 *
 * @example
 * ## Schema upload from file
 *
 * const fileSchema = await APISchema("api-schema-from-file", {
 *   zone: "example.com",
 *   schemaFile: "./openapi.yaml",
 *   name: "production-api-v2",
 *   enabled: false  // Upload but don't enable validation yet
 * });
 *
 * @example
 * ## Schema with typed OpenAPI object
 *
 * import type { OpenAPIV3 } from "openapi-types";
 *
 * const typedSchema: OpenAPIV3.Document = {
 *   openapi: "3.0.0",
 *   info: { title: "Typed API", version: "1.0.0" },
 *   paths: {
 *     "/health": {
 *       get: {
 *         operationId: "healthCheck",
 *         responses: { "200": { description: "OK" } }
 *       }
 *     }
 *   }
 * };
 *
 * const schema = await APISchema("typed-schema", {
 *   zone: myZone,
 *   schema: typedSchema
 * });
 */
export const APISchema = Resource("cloudflare::APISchema", async function (id, props) {
    const api = await createCloudflareApi(props);
    // Resolve zone ID and name
    const zoneId = typeof props.zone === "string"
        ? (await findZoneForHostname(api, props.zone)).zoneId
        : props.zone.id;
    if (this.phase === "delete") {
        if (this.output?.id) {
            await deleteSchema(api, zoneId, this.output.id);
        }
        return this.destroy();
    }
    // Load schema content
    const parsedSchema = props.schema;
    let schemaDetails;
    const schemaName = props.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
    if (this.phase === "update" && this.output?.name !== schemaName) {
        this.replace();
    }
    if (this.phase === "update" && this.output?.id) {
        // Check if we need to replace due to name, schema content change, or disabling validation
        if (schemaName !== this.output.name ||
            JSON.stringify(parsedSchema) !== JSON.stringify(this.output.schema) ||
            (this.output.enabled === true && props.enabled === false)) {
            // Name, schema content changed, or trying to disable validation - need to replace
            this.replace();
        }
        // Update existing schema (can only update validation_enabled)
        schemaDetails = await updateSchema(api, zoneId, this.output.id, {
            validation_enabled: props.enabled !== false,
        });
    }
    else {
        // Create new schema
        schemaDetails = await uploadSchema(api, zoneId, {
            file: yaml.stringify(parsedSchema),
            name: schemaName,
            validation_enabled: props.enabled !== false,
        });
    }
    return {
        id: schemaDetails.id,
        name: schemaDetails.name,
        schema: parsedSchema,
        source: schemaDetails.source,
        enabled: schemaDetails.validationEnabled,
    };
});
async function uploadSchema(api, zoneId, params) {
    const body = {
        source: params.file,
        name: params.name,
        kind: "openapi_v3",
        validation_enabled: params.validation_enabled ?? true,
    };
    const response = await api.post(`/zones/${zoneId}/schema_validation/schemas`, body);
    if (!response.ok) {
        await handleApiError(response, "uploading", "schema", params.name);
    }
    const data = (await response.json());
    return {
        id: data.result.schema_id,
        name: data.result.name,
        source: data.result.source,
        validationEnabled: data.result.validation_enabled,
        createdAt: data.result.created_at,
    };
}
async function updateSchema(api, zoneId, schemaId, params) {
    const response = await api.patch(`/zones/${zoneId}/schema_validation/schemas/${schemaId}`, params);
    if (!response.ok) {
        await handleApiError(response, "updating", "schema", schemaId);
    }
    const data = (await response.json());
    return {
        id: data.result.schema_id,
        name: data.result.name,
        source: data.result.source,
        validationEnabled: data.result.validation_enabled,
        createdAt: data.result.created_at,
    };
}
export async function deleteSchema(api, zoneId, schemaId) {
    const response = await api.delete(`/zones/${zoneId}/schema_validation/schemas/${schemaId}`);
    const data = (await response.json());
    if (response.status === 404) {
        return;
    }
    else if (response.status === 400 && data.errors[0].code === 19400) {
        // Bad request: schema with this ID does not exist
        return;
    }
    if (!response.ok) {
        await handleApiError(response, "deleting", "schema", schemaId);
    }
    else if (!data.success) {
        throw new CloudflareApiError(data.errors[0].message, response);
    }
}
/**
 * Get schema details
 */
export async function getSchema(api, zoneId, schemaId) {
    const response = await api.get(`/zones/${zoneId}/schema_validation/schemas/${schemaId}`);
    if (response.status === 404) {
        return null;
    }
    if (!response.ok) {
        await handleApiError(response, "getting", "schema", schemaId);
    }
    const data = (await response.json());
    return {
        id: data.result.schema_id,
        name: data.result.name,
        source: data.result.source,
        validationEnabled: data.result.validation_enabled,
        createdAt: data.result.created_at,
    };
}
/**
 * List all schemas in a zone
 */
export async function listSchemas(api, zoneId) {
    const response = await api.get(`/zones/${zoneId}/schema_validation/schemas`);
    if (!response.ok) {
        await handleApiError(response, "listing", "schemas", zoneId);
    }
    const data = (await response.json());
    return data.result.map((schema) => ({
        id: schema.schema_id,
        name: schema.name,
        source: schema.source,
        validationEnabled: schema.validation_enabled,
        createdAt: schema.created_at,
    }));
}
//# sourceMappingURL=api-schema.js.map