import { PutObjectCommand, GetObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import * as fs from 'fs';
import * as path from 'path';
import { randomUUID } from 'crypto';

const bucket = process.env.AWS_S3_BUCKET ?? '';
const region = process.env.AWS_S3_REGION ?? 'af-south-1';

let s3: S3Client | null = null;

function getS3(): S3Client | null {
  if (!process.env.AWS_ACCESS_KEY_ID || process.env.AWS_ACCESS_KEY_ID === 'your-key') {
    return null;
  }
  if (!s3) {
    s3 = new S3Client({
      region,
      credentials: {
        accessKeyId: process.env.AWS_ACCESS_KEY_ID,
        secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY ?? '',
      },
    });
  }
  return s3;
}

function localUploadDir(): string {
  const dir = path.join(process.cwd(), 'uploads');
  if (!fs.existsSync(dir)) {
    fs.mkdirSync(dir, { recursive: true });
  }
  return dir;
}

export class CloudStorageService {
  /** Upload buffer; returns public URL or local file URL for dev */
  static async upload(buffer: Buffer, key: string, mimeType: string): Promise<string> {
    const client = getS3();
    if (client && bucket) {
      await client.send(
        new PutObjectCommand({
          Bucket: bucket,
          Key: key,
          Body: buffer,
          ContentType: mimeType,
          ServerSideEncryption: 'AES256',
        })
      );
      return `https://${bucket}.s3.${region}.amazonaws.com/${encodeURIComponent(key)}`;
    }

    const safeName = key.replace(/[^a-zA-Z0-9._-]/g, '_');
    const filePath = path.join(localUploadDir(), `${randomUUID()}_${safeName}`);
    fs.writeFileSync(filePath, buffer);
    const base =
      process.env.PUBLIC_UPLOAD_BASE_URL ?? `http://localhost:${process.env.PORT ?? 4000}/uploads`;
    return `${base}/${path.basename(filePath)}`;
  }

  static async getSignedDownloadUrl(keyOrPath: string, expiresIn = 3600): Promise<string> {
    const client = getS3();
    if (client && bucket && !keyOrPath.startsWith('http://localhost')) {
      const key = keyOrPath.includes('amazonaws.com')
        ? decodeURIComponent(keyOrPath.split('.com/')[1] ?? keyOrPath)
        : keyOrPath;
      const cmd = new GetObjectCommand({ Bucket: bucket, Key: key });
      return getSignedUrl(client, cmd, { expiresIn });
    }
    return keyOrPath;
  }

  /** Reserved for S3 CopyObject to archive/ prefix; metadata-only soft delete handled in DB */
  static async archiveObject(_fileUrl: string, _archiveKey: string): Promise<void> {
    /* Implement CopyObject + DeleteObject when bucket credentials are live */
  }
}
