import { env } from "../../../../env.js";
import { getLogger } from "../../../../logger.js";
import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
import { getSignedUrl } from "@aws-sdk/s3-request-presigner";
import { NodeHttpHandler } from "@smithy/node-http-handler";

//#region src/domains/run/services/blob-storage/s3-provider.ts
const logger = getLogger("S3BlobStorageProvider");
var S3BlobStorageProvider = class {
	client;
	bucket;
	constructor() {
		const bucket = env.BLOB_STORAGE_S3_BUCKET;
		const accessKeyId = env.BLOB_STORAGE_S3_ACCESS_KEY_ID;
		const secretAccessKey = env.BLOB_STORAGE_S3_SECRET_ACCESS_KEY;
		const region = env.BLOB_STORAGE_S3_REGION;
		const missing = [
			["BLOB_STORAGE_S3_BUCKET", bucket],
			["BLOB_STORAGE_S3_ACCESS_KEY_ID", accessKeyId],
			["BLOB_STORAGE_S3_SECRET_ACCESS_KEY", secretAccessKey],
			["BLOB_STORAGE_S3_REGION", region]
		].filter(([, value]) => !value).map(([key]) => key);
		if (missing.length > 0) throw new Error(`S3 blob storage requires ${missing.join(", ")}`);
		this.bucket = bucket;
		this.client = new S3Client({
			endpoint: env.BLOB_STORAGE_S3_ENDPOINT,
			region,
			credentials: {
				accessKeyId,
				secretAccessKey
			},
			forcePathStyle: env.BLOB_STORAGE_S3_FORCE_PATH_STYLE,
			requestHandler: new NodeHttpHandler({
				connectionTimeout: 5e3,
				requestTimeout: 3e4
			})
		});
		logger.info({
			bucket: this.bucket,
			endpoint: env.BLOB_STORAGE_S3_ENDPOINT,
			region
		}, "Initializing S3 blob storage provider");
	}
	async upload(params) {
		logger.debug({
			key: params.key,
			contentType: params.contentType
		}, "Uploading to S3");
		try {
			await this.client.send(new PutObjectCommand({
				Bucket: this.bucket,
				Key: params.key,
				Body: params.data,
				ContentType: params.contentType
			}));
		} catch (error) {
			logger.error({
				key: params.key,
				bucket: this.bucket,
				error
			}, "S3 upload failed");
			throw new Error(`S3 upload failed for key ${params.key}: ${error instanceof Error ? error.message : String(error)}`);
		}
	}
	async download(key) {
		logger.debug({ key }, "Downloading from S3");
		try {
			const response = await this.client.send(new GetObjectCommand({
				Bucket: this.bucket,
				Key: key
			}));
			const bodyBytes = await response.Body?.transformToByteArray();
			if (!bodyBytes) throw new Error(`Empty response body for key: ${key}`);
			return {
				data: bodyBytes,
				contentType: response.ContentType || "application/octet-stream"
			};
		} catch (error) {
			logger.error({
				key,
				bucket: this.bucket,
				error
			}, "S3 download failed");
			throw new Error(`S3 download failed for key ${key}: ${error instanceof Error ? error.message : String(error)}`);
		}
	}
	async delete(key) {
		logger.debug({ key }, "Deleting from S3");
		try {
			await this.client.send(new DeleteObjectCommand({
				Bucket: this.bucket,
				Key: key
			}));
		} catch (error) {
			logger.error({
				key,
				bucket: this.bucket,
				error
			}, "S3 delete failed");
			throw new Error(`S3 delete failed for key ${key}: ${error instanceof Error ? error.message : String(error)}`);
		}
	}
	async getPresignedUrl(key, expiresInSeconds) {
		const expiry = expiresInSeconds ?? env.BLOB_STORAGE_PRESIGNED_URL_EXPIRY_SECONDS;
		logger.debug({
			key,
			expiry
		}, "Generating presigned URL");
		try {
			return await getSignedUrl(this.client, new GetObjectCommand({
				Bucket: this.bucket,
				Key: key
			}), { expiresIn: expiry });
		} catch (error) {
			logger.error({
				key,
				bucket: this.bucket,
				error
			}, "S3 presigned URL generation failed");
			throw new Error(`S3 presigned URL failed for key ${key}: ${error instanceof Error ? error.message : String(error)}`);
		}
	}
};

//#endregion
export { S3BlobStorageProvider };