import { Resource } from "../resource.js";
import { logger } from "../util/logger.js";
import { SentryApi } from "./api.js";
/**
 * Create and manage Sentry client keys
 *
 * @example
 * // Create a basic Sentry client key:
 * const key = await ClientKey("my-key", {
 *   name: "My Key",
 *   project: "my-project",
 *   organization: "my-org"
 * });
 *
 * @example
 * // Create a client key with rate limiting:
 * const key = await ClientKey("rate-limited-key", {
 *   name: "Rate Limited Key",
 *   project: "my-project",
 *   organization: "my-org",
 *   rateLimit: {
 *     window: 3600, // 1 hour
 *     count: 1000   // 1000 events per hour
 *   }
 * });
 *
 * @example
 * // Create a client key for a specific use case:
 * const key = await ClientKey("profiling-key", {
 *   name: "Profiling Key",
 *   project: "my-project",
 *   organization: "my-org",
 *   useCase: "profiling"
 * });
 *
 * @example
 * // Create or adopt an existing key with the same name:
 * const key = await ClientKey("existing-key", {
 *   name: "Existing Key",
 *   project: "my-project",
 *   organization: "my-org",
 *   adopt: true
 * });
 */
export const ClientKey = Resource("sentry::ClientKey", async function (id, props) {
    const api = new SentryApi({ authToken: props.authToken });
    // it's possible that `this.output.name` is undefined because a previous version
    // of alchemy had a bug where it didn't set the name on the output
    // so, we try to find the key by ID and use the name from the API response
    const lookupName = async () => {
        if (!this.output?.id) {
            // not running in the update phase
            return undefined;
        }
        else if (this.output.name) {
            return this.output.name;
        }
        const name = (await getClientKeyName(api, {
            organization: props.organization,
            project: props.project,
            keyId: this.output.id,
        }))?.name;
        if (name) {
            this.output.name = name;
        }
        return name;
    };
    const clientKeyName = props.name ?? (await lookupName()) ?? this.scope.createPhysicalName(id);
    if (this.phase === "update") {
        if (this.output.name !== clientKeyName) {
            this.replace();
        }
    }
    if (this.phase === "delete") {
        try {
            if (this.output?.id) {
                const response = await api.delete(`/projects/${props.organization}/${props.project}/keys/${this.output.id}/`);
                if (!response.ok && response.status !== 404) {
                    logger.error("Error deleting client key:", response.statusText);
                }
            }
        }
        catch (error) {
            logger.error("Error deleting client key:", error);
        }
        return this.destroy();
    }
    else {
        try {
            let response;
            if (this.phase === "update" && this.output?.id) {
                response = await api.put(`/projects/${props.organization}/${props.project}/keys/${this.output.id}/`, props);
            }
            else {
                try {
                    response = await api.post(`/projects/${props.organization}/${props.project}/keys/`, props);
                }
                catch (error) {
                    // Check if this is a "key already exists" error and adopt is enabled
                    if ((props.adopt ?? this.scope.adopt) &&
                        error instanceof Error &&
                        error.message.includes("already exists") &&
                        clientKeyName) {
                        logger.log(`Client key '${clientKeyName}' already exists, adopting it`);
                        // Find the existing key by name
                        const existingKey = await findClientKeyByName(api, props.organization, props.project, clientKeyName);
                        if (!existingKey) {
                            throw new Error(`Failed to find existing client key '${clientKeyName}' for adoption`);
                        }
                        response = await api.get(`/projects/${props.organization}/${props.project}/keys/${existingKey.id}/`);
                    }
                    else {
                        throw error;
                    }
                }
            }
            if (!response.ok) {
                throw new Error(`API error: ${response.statusText}`);
            }
            const data = (await response.json());
            return {
                ...props,
                id: data.id,
                name: clientKeyName,
                label: data.label,
                public: data.public,
                secret: data.secret,
                projectId: data.projectId,
                isActive: data.isActive,
                dsn: data.dsn,
                browserSdkVersion: data.browserSdkVersion,
                browserSdk: data.browserSdk,
                dateCreated: data.dateCreated,
                dynamicSdkLoaderOptions: data.dynamicSdkLoaderOptions,
            };
        }
        catch (error) {
            logger.error("Error creating/updating client key:", error);
            throw error;
        }
    }
});
/**
 * Find a client key by name
 */
async function findClientKeyByName(api, organization, project, name) {
    const response = await api.get(`/projects/${organization}/${project}/keys/`);
    if (!response.ok) {
        throw new Error(`API error: ${response.statusText}`);
    }
    const keys = (await response.json());
    const key = keys.find((k) => k.name === name);
    return key ? { id: key.id } : null;
}
/**
 * Find a client key by ID
 */
async function getClientKeyName(api, { organization, project, keyId, }) {
    const response = await api.get(`/projects/${organization}/${project}/keys/${keyId}`);
    if (!response.ok) {
        throw new Error(`API error: ${response.statusText}`);
    }
    const key = (await response.json());
    return key ? { id: key.id, name: key.name } : null;
}
//# sourceMappingURL=client-key.js.map