import { Resource } from "../resource.js";
import { createPlanetScaleClient } from "./api.js";
import { ensureProductionBranchClusterSize, sanitizeClusterSize, waitForBranchReady, } from "./utils.js";
/**
 * Create or manage a PlanetScale database branch
 *
 * @example
 * // Create a branch from 'main'
 * const branch = await Branch("feature-123", {
 *   name: "feature-123",
 *   organization: "my-org",
 *   database: "my-database",
 *   parentBranch: "main"
 * });
 *
 * @example
 * // Create a branch from another branch object
 * const parentBranch = await Branch("staging", {
 *   name: "staging",
 *   organization: "my-org",
 *   database: "my-database",
 *   parentBranch: "main"
 * });
 *
 * const featureBranch = await Branch("feature-456", {
 *   name: "feature-456",
 *   organization: "my-org",
 *   database: "my-database",
 *   parentBranch: parentBranch // Using Branch object instead of string
 * });
 *
 * @example
 * // Create a branch from a backup
 * const branch = await Branch("restored-branch", {
 *   name: "restored-branch",
 *   organization: "my-org",
 *   database: "my-database",
 *   parentBranch: "main",
 *   backupId: "backup-123",
 *   clusterSize: "PS_10"
 * });
 */
export const Branch = Resource("planetscale::Branch", async function (id, props) {
    const adopt = props.adopt ?? this.scope.adopt;
    const api = createPlanetScaleClient(props);
    const branchName = props.name ?? this.output?.name ?? this.scope.createPhysicalName(id);
    const parentBranchName = !props.parentBranch
        ? "main"
        : typeof props.parentBranch === "string"
            ? props.parentBranch
            : props.parentBranch.name;
    const organization = 
    // @ts-expect-error - organizationId is a legacy thing, we keep this so we can destroy
    this.output?.organizationId ??
        props.organization ??
        (typeof props.database !== "string"
            ? props.database.organization
            : (process.env.PLANETSCALE_ORGANIZATION ??
                process.env.PLANETSCALE_ORG_ID));
    const database = 
    // @ts-expect-error - databaseName is a legacy thing, we keep this so we can destroy
    this.output?.databaseName ??
        (typeof props.database === "string"
            ? props.database
            : props.database.name);
    const shouldDelete = props.delete ?? false;
    if (!organization) {
        throw new Error("PlanetScale organization is required. Please set the `organization` property or the `PLANETSCALE_ORGANIZATION` environment variable.");
    }
    if (this.phase === "update" && this.output.name !== branchName) {
        // TODO(sam): maybe we don't need to replace? just branch again? or rename?
        this.replace();
    }
    if (this.phase === "delete") {
        if (shouldDelete && this.output?.name) {
            const response = await api.deleteBranch({
                path: {
                    organization,
                    database,
                    branch: this.output.name,
                },
                throwOnError: false,
            });
            if (response.error && response.response.status !== 404) {
                throw new Error(`Failed to delete branch: ${response.error.message}`, {
                    cause: response.error,
                });
            }
        }
        return this.destroy();
    }
    if (typeof props.parentBranch !== "string" && props.parentBranch) {
        await waitForBranchReady(api, organization, database, props.parentBranch.name);
    }
    // Check if branch exists
    const getResponse = await api.getBranch({
        path: {
            organization,
            database,
            branch: branchName,
        },
        throwOnError: false,
    });
    if (getResponse.error && getResponse.response.status !== 404) {
        // Error getting branch
        throw new Error(`Failed to get branch: ${getResponse.error.message}`, {
            cause: getResponse.error,
        });
    }
    if (getResponse.data) {
        // Branch exists
        if (!adopt) {
            throw new Error(`Branch ${branchName} already exists and adopt is false`);
        }
        const data = getResponse.data;
        const currentParentBranch = data.parent_branch || "main";
        // Validate region matches if specified
        if (props.region) {
            const actualSlug = data.region.slug;
            if (actualSlug !== props.region.slug) {
                throw new Error(`Branch "${branchName}" is in region "${actualSlug}" but expected "${props.region.slug}". ` +
                    `PlanetScale branch regions cannot be changed after creation. ` +
                    `Either update the region in your configuration to match, or create a new branch in the correct region.`);
            }
        }
        // Check immutable properties
        if (props.parentBranch && parentBranchName !== currentParentBranch) {
            throw new Error(`Cannot change parent branch from ${currentParentBranch} to ${parentBranchName}`);
        }
        if (this.output?.backupId) {
            console.warn("BackupID is set, but branch already exists, so it will be ignored");
        }
        if (this.output?.seedData) {
            console.warn("SeedData is set, but branch already exists, so it will be ignored");
        }
        // Update mutable properties if they've changed
        if (props.safeMigrations !== undefined) {
            await api[props.safeMigrations
                ? "enableSafeMigrations"
                : "disableSafeMigrations"]({
                path: {
                    organization,
                    database,
                    branch: branchName,
                },
            });
        }
        const clusterSize = props.clusterSize
            ? sanitizeClusterSize({
                size: props.clusterSize,
                kind: data.kind,
                arch: data.cluster_architecture === "aarch64" ? "arm" : "x86",
                region: data.region.slug,
            })
            : undefined;
        if (clusterSize && data.cluster_name !== clusterSize) {
            if (!props.isProduction) {
                throw new Error(`Cannot change cluster size of non-production branch ${branchName}`);
            }
            await ensureProductionBranchClusterSize(api, organization, database, branchName, data.kind, clusterSize);
        }
        return {
            ...props,
            name: branchName,
            parentBranch: currentParentBranch,
            createdAt: data.created_at,
            updatedAt: data.updated_at,
            htmlUrl: data.html_url,
            region: { slug: data.region.slug },
        };
    }
    let clusterSize;
    const parent = await waitForBranchReady(api, organization, database, parentBranchName);
    if (props.clusterSize) {
        clusterSize = sanitizeClusterSize({
            size: props.clusterSize,
            kind: parent.kind,
            arch: parent.cluster_architecture === "aarch64" ? "arm" : "x86",
            region: parent.region.slug,
        });
    }
    // Branch doesn't exist, create it
    const { data } = await api.createBranch({
        path: {
            organization,
            database,
        },
        body: {
            name: branchName,
            parent_branch: parentBranchName,
            backup_id: props.backupId,
            seed_data: props.seedData,
            region: props.region?.slug,
            // This is ignored unless props.backupId is provided
            cluster_size: clusterSize,
        },
    });
    // Handle safe migrations if specified
    if (props.safeMigrations !== undefined) {
        // We can't change the migrations mode if the branch is not ready
        await waitForBranchReady(api, organization, database, branchName);
        await api[props.safeMigrations ? "enableSafeMigrations" : "disableSafeMigrations"]({
            path: {
                organization,
                database,
                branch: branchName,
            },
        });
    }
    // Handle cluster size update if specified
    if (clusterSize) {
        await ensureProductionBranchClusterSize(api, organization, database, branchName, data.kind, clusterSize);
    }
    return {
        ...props,
        name: branchName,
        parentBranch: data.parent_branch,
        createdAt: data.created_at,
        updatedAt: data.updated_at,
        htmlUrl: data.html_url,
        region: { slug: data.region.slug },
    };
});
//# sourceMappingURL=branch.js.map