"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateS3Service = generateS3Service;
const generator_1 = require("@postxl/generator");
function generateS3Service({ config, service }) {
    const imports = generator_1.ImportGenerator
        //
        .from(service.location)
        .add(config);
    return `
import { GetObjectCommand, PutObjectCommand, S3Client } from '@aws-sdk/client-s3'
import { Injectable, Logger } from '@nestjs/common'

import { generateRandomAlphanumericString } from '@postxl/utils'

${imports.generate()}

@Injectable()
export class ${service.name} {
  private readonly logger = new Logger(${service.name}.name)
  private readonly s3: S3Client

  /**
   * Normalize the bucket name by removing the "s3://" prefix, any leading slashes and returning the first part (bucket name).
   */
  get normalizedBucket(): string {
    let url = this.config.config.bucket

    // Remove the "s3://" prefix if it exists
    if (url.startsWith('s3://')) {
      url = url.slice(5)
    }

    // Remove any leading slashes
    url = url.replace(/^\\/+/, '')

    // Split the URL by the first slash and return the first part (bucket name)
    return url.split('/')[0]
  }

  constructor(private readonly config: ${config.name}) {
    this.s3 = new S3Client({
      credentials: this.config.config.useCredentials
        ? {
            accessKeyId: this.config.config.accessKey ?? '',
            secretAccessKey: this.config.config.secretAccessKey ?? '',
          }
        : undefined,
      region: this.config.config.region,
    })
  }

  /**
   * Get file from AWS S3 bucket.
   */
  public async getFile(key: string) {
    const command = new GetObjectCommand({
      Bucket: this.normalizedBucket,
      Key: key,
    })

    const response = await this.s3.send(command)
    if (!response.Body) {
      return null
    }
    return response.Body.transformToByteArray()
  }

  /**
   * Uploads a file to the AWS S3 bucket.
   */
  public async send(stream: NodeJS.ReadableStream, uuid: string, extension?: string): Promise<string> {
    this.logger.log('Uploading to S3')

    const key = generateS3Key(uuid, extension)
    const command = new PutObjectCommand({
      Bucket: this.normalizedBucket,
      Key: key,
      Body: await streamToBuffer(stream),
    })

    await this.s3.send(command)

    const fileUrl = \`https://\${this.normalizedBucket}.s3.\${this.config.config.region}.amazonaws.com/\${key}\`
    this.logger.log(\`Uploaded to S3 to \${fileUrl}\`)

    return key
  }
}

const streamToBuffer = (stream: NodeJS.ReadableStream): Promise<Buffer> =>
  new Promise((resolve, reject) => {
    const chunks: Buffer[] = []

    stream.on('data', (chunk: Buffer) => chunks.push(chunk))
    stream.on('end', () => resolve(Buffer.concat(chunks)))
    stream.on('error', (err: any) => {
      // Ensure the error is wrapped in an Error object
      const error = err instanceof Error ? err : new Error(String(err))
      reject(error)
    })
  })

const generateS3Key = (uuid: string, extension?: string | null): string => {
  // S3 performance is tied to the file prefix. By creating more prefixes,
  // we improve S3 performance (https://docs.aws.amazon.com/AmazonS3/latest/dev/optimizing-performance.html).
  const subfolder = generateRandomAlphanumericString(2)

  let key = \`\${subfolder}/\${uuid}\`
  if (extension) {
    key += '.' + extension
  }
  return key
}`;
}
//# sourceMappingURL=s3.service.generator.js.map