

import {
  S3Client,
  PutObjectCommand,
  DeleteObjectCommand,
  ListObjectsV2Command,
  DeleteObjectsCommand,
} from '@aws-sdk/client-s3';

import { IStorageDriver } from "../interface/storage.interface";
interface S3Config {
  accessKeyId: string;
  secretAccessKey: string;
  bucket: string;
  region?: string;
  endpointUrl?: string;
  cdnUrl?: string;
}

export class S3Driver implements IStorageDriver {
  private client: S3Client;
  constructor(private config: S3Config) {
    this.client = new S3Client({
      region: config.region || 'us-east-1',
      endpoint: config.endpointUrl,
      forcePathStyle: true,
      responseChecksumValidation: 'WHEN_REQUIRED',
      requestChecksumCalculation: 'WHEN_REQUIRED',
      credentials: {
        accessKeyId: config.accessKeyId,
        secretAccessKey: config.secretAccessKey,
      },
    });
  }

  private extractKeyFromUrl(fileUrl: string): string {
  const url = new URL(fileUrl);

  // remove leading slash
  let key = url.pathname.startsWith("/")
    ? url.pathname.slice(1)
    : url.pathname;

  // remove bucket folder if exists (invoiceg2g/)
  if (key.startsWith(this.config.bucket + "/")) {
    key = key.replace(this.config.bucket + "/", "");
  }

  return decodeURIComponent(key);
}


  async upload(
    file: Buffer,
    key: string,
    mimeType?: string,
  ): Promise<string> {
    await this.client.send(
      new PutObjectCommand({
        Bucket: this.config.bucket,
        Key: key,
        Body: file,
        ContentType: mimeType || 'application/octet-stream',

        // ❌ do NOT add ACL
        // ❌ do NOT add checksumAlgorithm
      }),
    );

    return key;
  }



  async delete(fileUrl: string): Promise<void> {
  try {
    const key = this.extractKeyFromUrl(fileUrl);
    await this.client.send(
      new DeleteObjectCommand({
        Bucket: this.config.bucket,
        Key: key,
      }),
    );

    console.log(`Successfully deleted: ${key}`);
  } catch (err) {
    console.error("Delete error:", err);
    throw err;
  }
}


  getUrl(key: string): string {
    if (this.config.cdnUrl) {
      return `${this.config.cdnUrl}/${key}`;
    }
    return `${this.config.endpointUrl}/${this.config.bucket}/${key}`;
  }


 async getAvailableImages(): Promise<{ Key?: string }[]> {
  const params = {
    Bucket:  this.config.bucket,
  };

  try {
    const command = new ListObjectsV2Command(params);
    const response = await this.client.send(command);

    if (response.Contents) {
      // Filter for common image file extensions (optional)
      const images = response.Contents.filter(item => {
        const key = item.Key?.toLowerCase();
        return key?.endsWith('.jpg') || key?.endsWith('.jpeg') || key?.endsWith('.png') || key?.endsWith('.gif');
      });

      console.log(`Found ${images.length} images:`);
      // Log the keys (filenames) of the available images
      images.forEach(image => console.log(image.Key));
      return images;
    } else {
      console.log("No images found in the bucket.");
      return [];
    }
  } catch (err) {
    console.error("Error listing objects from S3:", err);
    throw err;
  }
};

  async deleteAllImages(): Promise<void> {
    try {
      const images = await this.getAvailableImages();
      if (images.length === 0) {
        console.log("No images to delete.");
        return;
      }

      for (const image of images) {
        if (image.Key) {
          await this.client.send(
            new DeleteObjectCommand({
              Bucket: this.config.bucket,
              Key: image.Key,
            }),
          );
        }
      }
      console.log(`Successfully deleted ${images.length} images.`);
    } catch (err) {
      console.error("Error deleting images from S3:", err);
      throw err;
    }
  }


  
}
