import {
  S3Client,
  PutObjectCommand,
  GetObjectCommand,
  DeleteObjectCommand,
  CreateMultipartUploadCommand,
  UploadPartCommand,
  CompleteMultipartUploadCommand,
  AbortMultipartUploadCommand,
} from '@aws-sdk/client-s3';
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
import { env } from '../config/env.js';

// S3 client for internal server-to-server communication
const s3Client = new S3Client({
  endpoint: env.S3_ENDPOINT,
  credentials: {
    accessKeyId: env.S3_ACCESS_KEY,
    secretAccessKey: env.S3_SECRET_KEY,
  },
  region: 'us-east-1',
  forcePathStyle: true,
  // Оптимизация для больших файлов
  requestHandler: {
    connectionTimeout: 300000, // 5 минут
    socketTimeout: 600000,     // 10 минут
  },
});

// S3 client for generating presigned URLs for browser access
// Uses the same credentials but will generate URLs with public endpoint
const s3ClientForPresigned = new S3Client({
  endpoint: env.S3_ENDPOINT,
  credentials: {
    accessKeyId: env.S3_ACCESS_KEY,
    secretAccessKey: env.S3_SECRET_KEY,
  },
  region: 'us-east-1',
  forcePathStyle: true,
});

export async function uploadFile(key, body, contentType) {
  const command = new PutObjectCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
    Body: body,
    ContentType: contentType,
  });

  await s3Client.send(command);
  return key;
}

export async function getPresignedUrl(key, expiresIn = env.S3_PRESIGNED_URL_EXPIRES_IN) {
  const command = new GetObjectCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
  });

  const signedUrl = await getSignedUrl(s3Client, command, { expiresIn });
  return signedUrl;
}

export async function deleteFile(key) {
  const command = new DeleteObjectCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
  });

  await s3Client.send(command);
  return true;
}

export function getImageInputKey(filename, userId, folder = env.S3_IMAGES_INPUT_FOLDER) {
  const timestamp = Date.now();
  const ext = filename.split('.').pop() || 'jpg';
  return `${folder}/${userId}/${timestamp}-${filename}`;
}

export function getVideoInputKey(filename, userId, folder = 'videos_input') {
  const timestamp = Date.now();
  const ext = filename.split('.').pop() || 'mp4';
  return `${folder}/${userId}/${timestamp}-${filename}`;
}

// ──────────────────────────────
// Multipart Upload для прямой загрузки в S3
// ──────────────────────────────

/**
 * Инициировать multipart upload
 */
export async function createMultipartUpload(key, contentType) {
  const command = new CreateMultipartUploadCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
    ContentType: contentType,
  });

  const result = await s3Client.send(command);
  return {
    uploadId: result.UploadId,
    key,
  };
}

/**
 * Создать presigned URL для загрузки части файла
 * Возвращает URL для прямой загрузки из браузера через nginx proxy
 */
export async function getPresignedPartUrl(key, uploadId, partNumber, expiresIn = 3600) {
  const command = new UploadPartCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
    UploadId: uploadId,
    PartNumber: partNumber,
  });

  // Для presigned URL используем endpoint который совпадает с public endpoint
  // Браузер будет отправлять запрос на https://uno-click.pip-test.ru/s3-upload/uno-click/
  // Нginx будет проксировать на minio:9000/uno-click/
  // MinIO проверяет подпись используя только путь и query параметры, не host
  const signedUrl = await getSignedUrl(s3ClientForPresigned, command, { expiresIn });
  
  // Заменяем внутренний endpoint на публичный для доступа из браузера
  // Превращаем http://minio:9000/uno-click/... в https://uno-click.pip-test.ru/s3-upload/uno-click/...
  const publicUrl = signedUrl.replace(
    `${env.S3_ENDPOINT}/${env.S3_BUCKET}/`,
    env.S3_PUBLIC_ENDPOINT
  );
  
  return publicUrl;
}

/**
 * Завершить multipart upload
 */
export async function completeMultipartUpload(key, uploadId, parts) {
  const command = new CompleteMultipartUploadCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
    UploadId: uploadId,
    MultipartUpload: {
      Parts: parts.map((p, index) => ({
        PartNumber: index + 1,
        ETag: p.ETag,
      })),
    },
  });

  const result = await s3Client.send(command);
  return {
    key,
    location: result.Location,
    bucket: result.Bucket,
    etag: result.ETag,
  };
}

/**
 * Отменить multipart upload
 */
export async function abortMultipartUpload(key, uploadId) {
  const command = new AbortMultipartUploadCommand({
    Bucket: env.S3_BUCKET,
    Key: key,
    UploadId: uploadId,
  });

  await s3Client.send(command);
  return true;
}
