import * as fs from 'fs';
import * as path from 'path';
import { Injectable } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { S3Client, PutObjectCommand, DeleteObjectCommand } from '@aws-sdk/client-s3';
import { v4 as uuidv4 } from 'uuid';
import { PrismaService } from '../../prisma/prisma.service';

@Injectable()
export class MediaService {
  private s3: S3Client | null = null;
  private bucket: string;
  private publicUrl: string;
  private useLocal: boolean;
  private uploadsDir: string;

  constructor(
    private prisma: PrismaService,
    private config: ConfigService,
  ) {
    const accountId = config.get('R2_ACCOUNT_ID');
    this.useLocal = !accountId;
    this.bucket = config.get('R2_BUCKET_NAME') ?? '';
    this.publicUrl = config.get('R2_PUBLIC_URL') ?? '';
    this.uploadsDir = path.join(process.cwd(), 'uploads');

    if (this.useLocal) {
      if (!fs.existsSync(this.uploadsDir)) fs.mkdirSync(this.uploadsDir, { recursive: true });
    } else {
      this.s3 = new S3Client({
        endpoint: `https://${accountId}.r2.cloudflarestorage.com`,
        credentials: {
          accessKeyId: config.get('R2_ACCESS_KEY_ID') ?? '',
          secretAccessKey: config.get('R2_SECRET_ACCESS_KEY') ?? '',
        },
        region: 'auto',
      });
    }
  }

  async upload(file: Express.Multer.File, ownerId: string) {
    const key = `${uuidv4()}-${file.originalname.replace(/[^a-zA-Z0-9._-]/g, '_')}`;

    let url: string;
    if (this.useLocal) {
      fs.writeFileSync(path.join(this.uploadsDir, key), file.buffer);
      const port = this.config.get('PORT') ?? 3000;
      url = `http://localhost:${port}/uploads/${key}`;
    } else {
      await this.s3!.send(
        new PutObjectCommand({
          Bucket: this.bucket,
          Key: key,
          Body: file.buffer,
          ContentType: file.mimetype,
        }),
      );
      url = `${this.publicUrl}/${key}`;
    }

    return this.prisma.media.create({
      data: { ownerId, url, key, mimeType: file.mimetype, size: file.size },
    });
  }

  async delete(id: string, ownerId: string) {
    const media = await this.prisma.media.findFirst({ where: { id, ownerId } });
    if (!media) return;

    if (this.useLocal) {
      const filePath = path.join(this.uploadsDir, media.key);
      if (fs.existsSync(filePath)) fs.unlinkSync(filePath);
    } else {
      await this.s3!.send(new DeleteObjectCommand({ Bucket: this.bucket, Key: media.key }));
    }
    return this.prisma.media.delete({ where: { id } });
  }
}
