import { CreateAccessKeyCommand, CreateUserCommand, GetUserCommand, IAMClient, PutUserPolicyCommand } from "@aws-sdk/client-iam";
import { CreateBucketCommand, HeadBucketCommand, PutBucketVersioningCommand, S3Client } from "@aws-sdk/client-s3";

//#region src/deploy/backup-provisioner.ts
/**
* Generate a random suffix for unique resource names
*/
function randomSuffix() {
	return Math.random().toString(36).substring(2, 8);
}
/**
* Sanitize a name for AWS resources (lowercase alphanumeric and hyphens)
*/
function sanitizeName(name) {
	return name.toLowerCase().replace(/[^a-z0-9-]/g, "-");
}
/**
* Create AWS clients with optional profile credentials
*/
async function createAwsClients(region, profile, endpoint) {
	const config = { region };
	if (profile) {
		const { fromIni } = await import("@aws-sdk/credential-providers");
		config.credentials = fromIni({ profile });
	}
	if (endpoint) {
		config.endpoint = endpoint;
		config.forcePathStyle = true;
		config.credentials = {
			accessKeyId: "test",
			secretAccessKey: "test"
		};
	}
	return {
		s3: new S3Client(config),
		iam: new IAMClient(config)
	};
}
/**
* Check if an S3 bucket exists
*/
async function bucketExists(s3, bucketName) {
	try {
		await s3.send(new HeadBucketCommand({ Bucket: bucketName }));
		return true;
	} catch (error) {
		if (error.name === "NotFound") return false;
		if (error.$metadata?.httpStatusCode === 403) return true;
		throw error;
	}
}
/**
* Check if an IAM user exists
*/
async function userExists(iam, userName) {
	try {
		await iam.send(new GetUserCommand({ UserName: userName }));
		return true;
	} catch (error) {
		const errorName = error.name;
		if (errorName === "NoSuchEntity" || errorName === "NoSuchEntityException") return false;
		throw error;
	}
}
/**
* Provision backup destination for a deployment.
*
* Creates AWS resources (S3 bucket, IAM user) and Dokploy destination if needed.
* Reuses existing resources from state when possible.
*/
async function provisionBackupDestination(options) {
	const { api, projectName, stage, config, existingState, logger, awsEndpoint } = options;
	if (existingState?.destinationId) try {
		await api.getDestination(existingState.destinationId);
		logger.log("   Using existing backup destination");
		return existingState;
	} catch {
		logger.log("   Existing destination not found, recreating...");
	}
	const aws = await createAwsClients(config.region, config.profile, awsEndpoint);
	const sanitizedProject = sanitizeName(projectName);
	const bucketName = existingState?.bucketName ?? `${sanitizedProject}-${stage}-backups-${randomSuffix()}`;
	const bucketAlreadyExists = await bucketExists(aws.s3, bucketName);
	if (!bucketAlreadyExists) {
		logger.log(`   Creating S3 bucket: ${bucketName}`);
		const createBucketParams = { Bucket: bucketName };
		if (config.region !== "us-east-1") createBucketParams.CreateBucketConfiguration = { LocationConstraint: config.region };
		await aws.s3.send(new CreateBucketCommand(createBucketParams));
		await aws.s3.send(new PutBucketVersioningCommand({
			Bucket: bucketName,
			VersioningConfiguration: { Status: "Enabled" }
		}));
	} else logger.log(`   Using existing S3 bucket: ${bucketName}`);
	const iamUserName = existingState?.iamUserName ?? `dokploy-backup-${sanitizedProject}-${stage}`;
	const iamUserAlreadyExists = await userExists(aws.iam, iamUserName);
	if (!iamUserAlreadyExists) {
		logger.log(`   Creating IAM user: ${iamUserName}`);
		await aws.iam.send(new CreateUserCommand({ UserName: iamUserName }));
	} else logger.log(`   Using existing IAM user: ${iamUserName}`);
	const policyDocument = {
		Version: "2012-10-17",
		Statement: [{
			Effect: "Allow",
			Action: [
				"s3:GetObject",
				"s3:PutObject",
				"s3:DeleteObject",
				"s3:ListBucket",
				"s3:GetBucketLocation"
			],
			Resource: [`arn:aws:s3:::${bucketName}`, `arn:aws:s3:::${bucketName}/*`]
		}]
	};
	logger.log("   Updating IAM policy");
	await aws.iam.send(new PutUserPolicyCommand({
		UserName: iamUserName,
		PolicyName: "DokployBackupAccess",
		PolicyDocument: JSON.stringify(policyDocument)
	}));
	let accessKeyId;
	let secretAccessKey;
	if (existingState?.iamAccessKeyId && existingState?.iamSecretAccessKey) {
		logger.log("   Using existing IAM access key");
		accessKeyId = existingState.iamAccessKeyId;
		secretAccessKey = existingState.iamSecretAccessKey;
	} else {
		logger.log("   Creating IAM access key");
		const accessKeyResult = await aws.iam.send(new CreateAccessKeyCommand({ UserName: iamUserName }));
		if (!accessKeyResult.AccessKey) throw new Error("Failed to create IAM access key");
		accessKeyId = accessKeyResult.AccessKey.AccessKeyId;
		secretAccessKey = accessKeyResult.AccessKey.SecretAccessKey;
	}
	const destinationName = `${sanitizedProject}-${stage}-s3`;
	logger.log(`   Creating Dokploy destination: ${destinationName}`);
	const { destination, created } = await api.findOrCreateDestination(destinationName, {
		accessKey: accessKeyId,
		secretAccessKey,
		bucket: bucketName,
		region: config.region
	});
	if (created) logger.log("   ✓ Dokploy destination created");
	else logger.log("   ✓ Using existing Dokploy destination");
	try {
		await api.testDestinationConnection(destination.destinationId);
		logger.log("   ✓ Destination connection verified");
	} catch (error) {
		logger.log(`   ⚠ Warning: Could not verify destination connection: ${error}`);
	}
	return {
		bucketName,
		bucketArn: `arn:aws:s3:::${bucketName}`,
		iamUserName,
		iamAccessKeyId: accessKeyId,
		iamSecretAccessKey: secretAccessKey,
		destinationId: destination.destinationId,
		region: config.region,
		createdAt: existingState?.createdAt ?? (/* @__PURE__ */ new Date()).toISOString()
	};
}

//#endregion
export { provisionBackupDestination };
//# sourceMappingURL=backup-provisioner-BEXoHTuC.mjs.map