import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
import * as fs from 'fs';
import { extname } from 'path';
import { IFile } from '../types/interface';

@Injectable()
export class UploadService {
  async saveImage(
    file: Express.Multer.File,
    folderName: string = 'temp',
  ): Promise<IFile> {
    if (!file) {
      throw new HttpException('File not uploaded', HttpStatus.BAD_REQUEST);
    }
    // IFile
    const uploadDir = `uploads/${folderName}`;
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    const timestamp = Date.now();
    const originalName = file.originalname.split('.')[0];
    const extension = extname(file.originalname);
    const uniqueFilename = `${originalName}_${timestamp}${extension}`;
    const filePath = `${uploadDir}/${uniqueFilename}`;

    await fs.promises.writeFile(filePath, file.buffer);

    const fileData: IFile = {
      file_name: filePath,
      original_name: file.originalname,
      file_size: file.size,
      mime_type: file.mimetype,
    };

    return fileData;
  }

  async saveImages(
    files: Express.Multer.File[],
    folderName: string = 'common',
  ): Promise<IFile[]> {
    if (!files) {
      throw new HttpException('Files not uploaded', HttpStatus.BAD_REQUEST);
    }
    const uploadDir = `uploads/${folderName}`;
    if (!fs.existsSync(uploadDir)) {
      fs.mkdirSync(uploadDir, { recursive: true });
    }
    const fileNames: IFile[] = [];
    for (const file of files) {
      const fileData = await this.saveImage(file, folderName);
      fileNames.push(fileData);
    }
    return fileNames;
  }

  async removeImage(fileData: IFile): Promise<void> {
    if (!fs.existsSync(fileData?.file_name)) {
      return;
    }
    await fs.promises.unlink(fileData?.file_name);
  }

  async removeImages(fileDataArray: IFile[]): Promise<void> {
    for (const fileData of fileDataArray) {
      await this.removeImage(fileData);
    }
  }

  // move image and return new path
  async moveImage(oldData: IFile, movedFolderName: string): Promise<IFile> {
    const movedFolder = `uploads/${movedFolderName}`;
    if (!fs.existsSync(movedFolder)) {
      fs.mkdirSync(movedFolder, { recursive: true });
    }
    const host = process.env.SERVER_HOST || 'http://localhost:8000';

    const timestamp = Date.now();
    // remove hostname from file_name if exist
    const filePath = oldData.file_name.replace(`${host}/`, '');

    const extension = extname(filePath);
    const originalName = oldData.original_name.split('.')[0];
    const uniqueFilename = `${originalName}_${timestamp}${extension}`;
    const newPath = `${movedFolder}/${uniqueFilename}`;
    await fs.promises.copyFile(filePath, newPath);
    // this.removeOldTempFiles();
    return {
      ...oldData,
      file_name: newPath,
    };
  }

  // move images and return new paths
  async moveImages(
    oldDataList: IFile[],
    movedFolderName: string,
  ): Promise<IFile[]> {
    const movedFolder = `uploads/${movedFolderName}`;
    if (!fs.existsSync(movedFolder)) {
      fs.mkdirSync(movedFolder, { recursive: true });
    }
    const newDataList: IFile[] = [];
    for (const oldData of oldDataList) {
      const newData = await this.moveImage(oldData, movedFolderName);
      newDataList.push(newData);
    }
    this.removeOldTempFiles();
    return newDataList;
  }

  // remove all old files who exist in temp folder which is store before current date
  async removeOldTempFile(filePath: string): Promise<void> {
    await fs.promises.unlink(filePath);
  }
  // remove all old files who exist in temp folder which is store before current date
  async removeOldTempFiles(tempFolderName: string = 'temp'): Promise<void> {
    const tempFolder = `uploads/${tempFolderName}`;
    if (!fs.existsSync(tempFolder)) {
      return;
    }
    const files = await fs.promises.readdir(tempFolder);
    const now = Date.now();
    for (const file of files) {
      const filePath = `${tempFolder}/${file}`;
      const stats = await fs.promises.stat(filePath);
      const fileAge = now - stats.birthtimeMs;
      if (fileAge > 24 * 60 * 60 * 1000) {
        await fs.promises.unlink(filePath);
      }
    }
  }
}
