import { File } from '@nest-lab/fastify-multer';
import { BadRequestException, Injectable, Logger } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';

import { ImageProcessingService } from './image-processing.service';
import { S3Service } from './s3.service';
import { UploaderMessage } from '../../../common/enums/message.enum';
import { FileType } from '../interfaces/file.interface';

@Injectable()
export class UploaderService {
  private readonly logger = new Logger(UploaderService.name);
  private readonly maxFileSize: number;
  private readonly allowedMimeTypes: string[];

  constructor(
    private readonly configService: ConfigService,
    private readonly s3Service: S3Service,
    private readonly imageProcessingService: ImageProcessingService,
  ) {
    this.maxFileSize = this.configService.get('MAX_FILE_SIZE', 1024 * 1024 * 100); // 100MB
    this.allowedMimeTypes = [
      'video/mp4',
      'video/webm',
      'video/ogg',
      'video/avi',
      'video/mov',
      'video/mkv',
      'audio/mp3',
      'audio/wav',
      'audio/ogg',
      'audio/webm',
      'audio/m4a',
      'audio/aac',
      'audio/flac',
      'audio/m4a',
      'image/jpeg',
      'image/png',
      'image/gif',
      'image/webp',
      'image/svg+xml',
      'image/tiff',
      'image/bmp',
      'application/pdf',
      'text/plain',
      'text/csv',
      'application/msword',
      'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
      'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
      'application/vnd.openxmlformats-officedocument.presentationml.presentation',
      'application/vnd.openxmlformats-officedocument.presentationml.slideshow',
      'application/vnd.ms-excel',
      'application/vnd.ms-powerpoint',
      'application/vnd.ms-excel.sheet.macroEnabled.12',
      'application/vnd.ms-powerpoint.presentation.macroEnabled.12',
      'application/vnd.ms-excel.template.macroEnabled.12',
      'application/vnd.ms-powerpoint.template.macroEnabled.12',
      'application/vnd.ms-excel.addin.macroEnabled.12',
      'application/vnd.ms-powerpoint.addin.macroEnabled.12',
      'application/vnd.ms-excel.sheet.binary.macroEnabled.12',
      'application/vnd.ms-powerpoint.presentation.binary.macroEnabled.12',
      'application/vnd.ms-excel.template.binary.macroEnabled.12',
      'application/vnd.ms-powerpoint.template.binary.macroEnabled.12',
      'application/vnd.ms-excel.addin.binary.macroEnabled.12',
    ];
  }

  async uploadMultiple(files: File[]) {
    return await Promise.all(files.map(file => this.uploadFile(file)));
  }

  /**
   * Handle file upload
   */
  async uploadFile(file: File) {
    if (!file || !file.buffer || !file.size) {
      throw new BadRequestException(UploaderMessage.UPLOAD_FILE_INVALID);
    }
    this.logger.log(`Uploading file: ${file.originalname}`);

    this.validateFile(file);

    const fileType = await this.determineFileType(file.mimetype);

    let uploadBuffer = file.buffer;
    let contentType = file.mimetype;
    let extensionOverride: string | undefined;

    if (fileType === 'image') {
      const processed = await this.imageProcessingService.processImage(file.buffer, file.mimetype);
      if (processed) {
        uploadBuffer = processed.buffer;
        contentType = processed.contentType;
        extensionOverride = processed.extension;
      }
    }

    const s3Key = this.s3Service.generateFileKey(file.originalname, fileType, extensionOverride);

    const s3Result = await this.s3Service.uploadFile(uploadBuffer, s3Key, contentType, {
      originalName: file.originalname,
      uploadedBy: 'admin',
    });

    this.logger.log(`File uploaded successfully: `);

    return {
      file: s3Result,
      url: s3Result.url,
    };
  }

  /**
   * Validate uploaded file
   */
  private validateFile(file: File): void {
    if (!file) throw new BadRequestException(UploaderMessage.UPLOAD_FILE_INVALID);

    if (file.size && file.size > this.maxFileSize)
      throw new BadRequestException(
        UploaderMessage.UPLOAD_FILE_TOO_LARGE.replace('[MAX_FILE_SIZE]', this.maxFileSize.toString()),
      );

    if (!this.allowedMimeTypes.includes(file.mimetype))
      throw new BadRequestException(
        UploaderMessage.UPLOAD_FILE_TYPE_NOT_SUPPORTED.replace('[MIME_TYPES]', file.mimetype),
      );
  }

  /**
   * Determine file type based on mimetype
   */
  private async determineFileType(mimetype: string): Promise<FileType> {
    if (mimetype.startsWith('video/')) {
      return 'video';
    } else if (mimetype.startsWith('audio/')) {
      return 'audio';
    } else if (mimetype.startsWith('image/')) {
      return 'image';
    } else if (mimetype.startsWith('text/')) {
      return 'text';
    } else if (mimetype.startsWith('application/')) {
      return 'document';
    }
    return 'unknown';
  }
}
