import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { v4 as uuidv4 } from 'uuid';
import multer from 'multer';
import sharp from 'sharp';
import { logger } from '../config/logger';
import { imageResolutions } from '../config/imageResolutions';


// Конфигурация для подключения к S3
const BUCKET_NAME = process.env.AWS_S3_BUCKET || '';
const REGION = process.env.AWS_REGION || 'ru-central1';
const AWS_ENDPOINT = process.env.AWS_ENDPOINT || '';
const ACCESS_KEY_ID = process.env.AWS_ACCESS_KEY_ID || '';
const SECRET_ACCESS_KEY = process.env.AWS_SECRET_ACCESS_KEY || '';

// Создаем клиент S3
export const s3Client = new S3Client({
  region: REGION,
  endpoint: AWS_ENDPOINT,
  credentials: {
    accessKeyId: ACCESS_KEY_ID,
    secretAccessKey: SECRET_ACCESS_KEY,
  },
  forcePathStyle: true, // Обязательно для REG.RU S3
});

// Наименование бакета
export const bucketName = BUCKET_NAME;

// Функция для изменения размеров и оптимизации изображения
const resizeAndOptimizeImage = async (buffer: Buffer, width: number, height: number, quality: number): Promise<Buffer> => {
  return await sharp(buffer)
      .resize(width, height, {
        fit: sharp.fit.inside
      })
      .webp({ quality })
      .toBuffer();
};

// Функция для получения конфигурации Multer-S3
const getMulterS3Config = (
    s3Client: S3Client,
    bucketName: string
) => {
  return multer({
    storage: multer.memoryStorage(), // Храним файл в памяти перед обработкой
    fileFilter: (req, file, cb) => {
      if (!file.mimetype.startsWith('image/')) {
        return cb(new Error('Разрешены только файлы изображений!'));
      }
      cb(null, true);
    },
  }).single('file'); // Обрабатываем один файл
};

// Middleware по умолчанию, использующее дефолтовый S3 клиент
export const multerUpload = getMulterS3Config(s3Client, bucketName);

// Функция для загрузки файла в S3 после оптимизации
export const uploadToS3 = async (
    s3Client: S3Client,
    bucketName: string,
    folder: string,
    file: Express.Multer.File,
    resolutionId: string,
    quality: number
) => {
  try {
    const selectedResolution = imageResolutions.find(r => r.id === resolutionId);
    if (!selectedResolution) {
      throw new Error('Недопустимое разрешение изображения');
    }

    // Оптимизируем изображение
    const optimizedBuffer = await resizeAndOptimizeImage(
        file.buffer,
        selectedResolution.width,
        selectedResolution.height,
        quality
    );

    // Генерируем уникальное имя файла
    const uniqueSuffix = Date.now() + '-' + Math.round(Math.random() * 1e9);
    const fileNameWithoutExt = file.originalname.replace(/\.[^.]+$/, '');
    const fileName = `${folder}/${uniqueSuffix}-${fileNameWithoutExt}.webp`;

    // Загружаем файл в S3
    const command = new PutObjectCommand({
      Bucket: bucketName,
      Key: fileName,
      Body: optimizedBuffer,
      ContentType: file.mimetype,
      ACL: 'public-read',
    });

    await s3Client.send(command);

    // Возвращаем URL загруженного файла
    return `https://${bucketName}.s3.regru.cloud/${fileName}`;
  } catch (error) {
    throw new Error(`Ошибка загрузки файла в S3: ${error}`);
  }
};

/**
 * Функция для загрузки буфера в S3
 * @param buffer       - Буфер для загрузки
 * @param folder       - Путь к папке в S3
 * @param filename     - Опциональное имя файла (если пусто, то будет сгенерирован UUID как имя)
 * @param mimetype     - MIME тип контента буфера
 * @param resolutionId - Опциональный идентификатор разрешения изображения
 * @param quality      - Опциональное значение качества при оптимизации
 * @returns URL загрущенного файла
 */
export const uploadBufferToS3 = async (
    buffer: Buffer,
    folder: string,
    filename?: string,
    mimetype?: string,
    resolutionId?: string,
    quality: number = 80
): Promise<string> => {
  try {
    // Генерация имени файла, если оно не задано
    const finalFilename = filename || `${uuidv4()}${mimetype ? getExtensionFromMimeType(mimetype) : '.bin'}`;

    // Создание ключа S3 (путь в бакете)
    const key = folder ? `${folder}/${finalFilename}` : finalFilename;

    const selectedResolution = imageResolutions.find(r => r.id === resolutionId);
    if (!selectedResolution) {
      throw new Error('Недопустимое разрешение изображения');
    }

    // Оптимизируем изображение
    const optimizedBuffer = await resizeAndOptimizeImage(
        buffer,
        selectedResolution.width,
        selectedResolution.height,
        quality
    );

    // Загрузка буфера в S3
    await s3Client.send(
        new PutObjectCommand({
          Bucket: bucketName,
          Key: key,
          Body: optimizedBuffer,
          ContentType: mimetype,
        })
    );

    // Возвращаем URL файла с заменой расширения
    const fileUrl = `https://${bucketName}.s3.regru.cloud/${key}`;
    logger.info(`Буфер успешно загружен в S3: ${key}`);
    return fileUrl;
  } catch (error) {
    logger.error('Ошибка загрузки буфера в S3', error);
    console.error(error);
    throw new Error('Ошибка загрузки буфера в S3');
  }
};

// Функция получения расширения файла из MIME типа
function getExtensionFromMimeType(mimetype: string): string {
  const mimeToExt: Record<string, string> = {
    'image/jpeg': '.jpg',
    'image/png': '.png',
    'image/gif': '.gif',
    'image/webp': '.webp',
    'image/svg+xml': '.svg',
    'application/pdf': '.pdf',
    'text/plain': '.txt',
    'text/html': '.html',
    'application/json': '.json',
  };

  return mimeToExt[mimetype] || '';
}

// Упрощенная версия uploadToS3 которая использует клиента и бакет по умолчанию
export const uploadFile = async (
    folder: string,
    file: Express.MulterS3.File,
    resolutionId: string,
    quality: number = 80
): Promise<string> => {
  return uploadToS3(s3Client, bucketName, folder, file, resolutionId, quality);
};