import { Injectable, BadRequestException } from '@nestjs/common';
import { writeFile } from 'fs/promises';
import * as fs from 'fs';
import * as path from 'path';
import sizeOf from 'image-size';
import { promises } from 'fs';
import axios from 'axios';
@Injectable()
export class MediasService {
  private ROOT_MEDIA_FOLDER = './public';

  async saveBase64Image(
    base64: string,
    filenamePrefix = 'image',
    folder: string,
    maxSizeInMB = 2,
  ): Promise<{
    filename: string;
    filepath: string;
    url: string;
    mimetype: string;
    width?: number;
    height?: number;
    sizeInKB: number;
  }> {
    let mimeType = '';
    let base64Data = '';

    const matches = base64.match(/^data:(.+);base64,(.*)$/);
    if (matches) {
      mimeType = matches[1];
      base64Data = matches[2];
    } else {
      base64Data = base64;
      mimeType = 'image/jpeg';
    }

    const buffer = Buffer.from(base64Data, 'base64');

    const sizeInBytes = buffer.length;
    const sizeInKB = Math.round(sizeInBytes / 1024);
    const sizeInMB = sizeInBytes / (1024 * 1024);
    if (sizeInMB > maxSizeInMB) {
      throw new BadRequestException(`Ảnh vượt quá giới hạn ${maxSizeInMB}MB`);
    }

    const extension = this._getExtensionFromMime(mimeType);
    if (!extension) {
      throw new BadRequestException('Không hỗ trợ loại ảnh này');
    }

    const fullPath = path.join(this.ROOT_MEDIA_FOLDER, folder);
    if (!fs.existsSync(fullPath)) {
      fs.mkdirSync(fullPath, { recursive: true });
    }

    const fileNameOnly = `${filenamePrefix}-${Date.now()}.${extension}`;
    const filepath = path.join(fullPath, fileNameOnly);
    const relativeUrl = path.join(folder, fileNameOnly).replace(/\\/g, '/');

    await writeFile(filepath, buffer);

    let dimensions: { width?: number; height?: number } = {};
    try {
      dimensions = sizeOf(buffer);
    } catch (_) {}

    return {
      filename: fileNameOnly,
      filepath,
      url: `/uploads/${relativeUrl}`, // nếu bạn serve thư mục public tại /uploads
      mimetype: mimeType,
      sizeInKB,
      width: dimensions.width,
      height: dimensions.height,
    };
  }

  async saveBufferImage(
    buffer: Buffer,
    filenamePrefix = 'image',
    folder: string,
    maxSizeInMB = 2,
    mimeType: string = 'png',
  ): Promise<{
    filename: string;
    filepath: string;
    url: string;
    mimetype: string;
    width?: number;
    height?: number;
    sizeInKB: number;
  }> {
    const sizeInBytes = buffer.length;
    const sizeInMB = sizeInBytes / (1024 * 1024);
    if (sizeInMB > maxSizeInMB) {
      throw new BadRequestException(`Ảnh vượt quá giới hạn ${maxSizeInMB}MB`);
    }
    const sizeInKB = Math.round(sizeInBytes / 1024);

    // Tạo thư mục nếu chưa có
    const fullPath = path.join(this.ROOT_MEDIA_FOLDER, folder);
    if (!fs.existsSync(fullPath)) {
      await promises.mkdir(fullPath, { recursive: true });
    }

    // Tạo tên file
    const fileNameOnly = `${filenamePrefix}-${Date.now()}.${mimeType}`;
    const filepath = path.join(fullPath, fileNameOnly);

    // Ghi file
    await writeFile(filepath, buffer);

    // Lấy kích thước ảnh
    let dimensions: { width?: number; height?: number } = {};
    try {
      dimensions = sizeOf(buffer);
    } catch (_) {
      // Không lấy được kích thước thì thôi
    }

    // Tạo url tương đối (giả sử serve public tại /uploads)
    const relativeUrl = path.join(folder, fileNameOnly).replace(/\\/g, '/');

    return {
      filename: fileNameOnly,
      filepath,
      url: `/uploads/${relativeUrl}`,
      mimetype: mimeType,
      sizeInKB,
      width: dimensions.width,
      height: dimensions.height,
    };
  }

  async downloadImageAndSave(
    url: string,
    folder: string,
    path: string,
  ): Promise<{
    filename: string;
    filepath: string;
    url: string;
    mimetype: string;
    width?: number;
    height?: number;
    sizeInKB: number;
  }> {
    try {
      const response = await axios.get<ArrayBuffer>(url, {
        responseType: 'arraybuffer',
      });

      const buffer = Buffer.from(response.data);

      const filename = await this.saveBufferImage(buffer, folder, path);

      return filename;
    } catch (error) {
      console.warn('Failed to download image:', url, error);
      throw error;
    }
  }

  async removeMediasFolder(filepath: string, folder: string): Promise<void> {
    if (!filepath) return;

    // Luôn xử lý path bắt đầu từ 'medias/filepaths'
    const relativePath = path.join('medias/' + folder, filepath); // ✅ chính xác từ input: khangpn/avatar-xxx.jpg
    const fullPath = path.join(this.ROOT_MEDIA_FOLDER, relativePath);

    const rootPath = path.resolve(this.ROOT_MEDIA_FOLDER);
    const resolvedFullPath = path.resolve(fullPath);

    if (!resolvedFullPath.startsWith(rootPath)) {
      throw new Error('Invalid: Cannot delete outside the specified directory');
    }

    try {
      // Xóa file avatar
      if (fs.existsSync(fullPath)) {
        await fs.promises.unlink(fullPath);
      }

      // Xóa folder username nếu rỗng (khangpn)
      const usernameFolder = path.dirname(fullPath); // => /public/medias/avatars/khangpn
      const files = await fs.promises.readdir(usernameFolder);
      if (files.length === 0) {
        await fs.promises.rmdir(usernameFolder);
      }
    } catch (error) {
      console.error(`Error when deleting avatar or folder: ${error.message}`);
    }
  }

  private _getExtensionFromMime(mime: string): string | null {
    const map = {
      'image/jpeg': 'jpg',
      'image/png': 'png',
      'image/gif': 'gif',
      'image/webp': 'webp',
    };
    return map[mime] || null;
  }

  private _getDatePath(): string[] {
    const now = new Date();
    const yyyy = now.getFullYear().toString();
    const mm = String(now.getMonth() + 1).padStart(2, '0');
    const dd = String(now.getDate()).padStart(2, '0');
    return [yyyy, mm, dd];
  }
}
