/**
 * 이미지 업로드 서비스
 * Base64 인코딩된 이미지를 파일로 저장
 *
 * 사용 전 sharp 패키지 설치 필요:
 * npm install sharp
 */

const path = require('path');
const fs = require('fs').promises;
const crypto = require('crypto');
const { execFileSync } = require('child_process');

// sharp는 선택적으로 사용 (설치되어 있지 않으면 리사이징 없이 저장)
let sharp;
try {
  sharp = require('sharp');
} catch (e) {
  console.warn('sharp 패키지가 설치되어 있지 않습니다. 이미지 리사이징이 비활성화됩니다.');
  console.warn('이미지 최적화를 위해 npm install sharp 를 실행하세요.');
}

// 업로드 디렉토리 설정
const UPLOAD_DIRS = {
  issues: path.join(__dirname, '../uploads/issues'),
  equipments: path.join(__dirname, '../uploads/equipments')
};
const UPLOAD_DIR = UPLOAD_DIRS.issues; // 기존 호환성 유지
const MAX_SIZE = { width: 1920, height: 1920 };
const QUALITY = 85;

/**
 * 업로드 디렉토리 확인 및 생성
 * @param {string} category - 카테고리 ('issues' 또는 'equipments')
 */
async function ensureUploadDir(category = 'issues') {
  const uploadDir = UPLOAD_DIRS[category] || UPLOAD_DIRS.issues;
  try {
    await fs.access(uploadDir);
  } catch {
    await fs.mkdir(uploadDir, { recursive: true });
  }
  return uploadDir;
}

/**
 * UUID 생성 (간단한 버전)
 */
function generateId() {
  return crypto.randomBytes(4).toString('hex');
}

/**
 * 타임스탬프 문자열 생성
 */
function getTimestamp() {
  const now = new Date();
  return now.toISOString().replace(/[-:T]/g, '').slice(0, 14);
}

/**
 * Base64 문자열에서 이미지 형식 추출
 * @param {string} base64String - Base64 인코딩된 이미지
 * @returns {string} 이미지 확장자 (jpg, png, etc)
 */
function getImageExtension(base64String) {
  const match = base64String.match(/^data:image\/(\w+);base64,/);
  if (match) {
    const format = match[1].toLowerCase();
    // jpeg를 jpg로 변환
    return format === 'jpeg' ? 'jpg' : format;
  }
  return 'jpg'; // 기본값
}

/**
 * Base64 이미지를 파일로 저장
 * @param {string} base64String - Base64 인코딩된 이미지 (data:image/...;base64,... 형식)
 * @param {string} prefix - 파일명 접두사 (예: 'issue', 'resolution', 'equipment')
 * @param {string} category - 저장 카테고리 ('issues' 또는 'equipments')
 * @returns {Promise<string|null>} 저장된 파일의 웹 경로 또는 null
 */
async function saveBase64Image(base64String, prefix = 'issue', category = 'issues') {
  try {
    if (!base64String || typeof base64String !== 'string') {
      return null;
    }

    // Base64 헤더가 없는 경우 처리
    let base64Data = base64String;
    if (base64String.includes('base64,')) {
      base64Data = base64String.split('base64,')[1];
    }

    // Base64 디코딩
    const buffer = Buffer.from(base64Data, 'base64');

    if (buffer.length === 0) {
      console.error('이미지 데이터가 비어있습니다.');
      return null;
    }

    // 디렉토리 확인
    const uploadDir = await ensureUploadDir(category);

    // 파일명 생성
    const timestamp = getTimestamp();
    const uniqueId = generateId();
    const extension = 'jpg'; // 모든 이미지를 JPEG로 저장
    const filename = `${prefix}_${timestamp}_${uniqueId}.${extension}`;
    const filepath = path.join(uploadDir, filename);

    // sharp가 설치되어 있으면 리사이징 및 최적화
    let saved = false;
    if (sharp) {
      try {
        await sharp(buffer)
          .resize(MAX_SIZE.width, MAX_SIZE.height, {
            fit: 'inside',
            withoutEnlargement: true
          })
          .jpeg({ quality: QUALITY })
          .toFile(filepath);
        saved = true;
      } catch (sharpError) {
        console.warn('sharp 처리 실패:', sharpError.message);
      }
    }

    // sharp 실패 시 ImageMagick으로 변환 시도 (HEIC 등)
    if (!saved) {
      try {
        const tmpInput = filepath + '.tmp';
        await fs.writeFile(tmpInput, buffer);
        execFileSync('magick', [tmpInput, '-resize', `${MAX_SIZE.width}x${MAX_SIZE.height}>`, '-quality', String(QUALITY), filepath]);
        await fs.unlink(tmpInput).catch(() => {});
        saved = true;
      } catch (magickError) {
        console.warn('ImageMagick 변환 실패:', magickError.message);
      }
    }

    // 모두 실패 시 원본 저장
    if (!saved) {
      await fs.writeFile(filepath, buffer);
    }

    // 웹 접근 경로 반환
    return `/uploads/${category}/${filename}`;
  } catch (error) {
    console.error('이미지 저장 실패:', error);
    return null;
  }
}

/**
 * 여러 Base64 이미지를 한번에 저장
 * @param {string[]} base64Images - Base64 이미지 배열
 * @param {string} prefix - 파일명 접두사
 * @returns {Promise<string[]>} 저장된 파일 경로 배열
 */
async function saveMultipleImages(base64Images, prefix = 'issue') {
  const paths = [];

  for (const base64 of base64Images) {
    if (base64) {
      const savedPath = await saveBase64Image(base64, prefix);
      if (savedPath) {
        paths.push(savedPath);
      }
    }
  }

  return paths;
}

/**
 * 파일 삭제
 * @param {string} webPath - 웹 경로 (예: /uploads/issues/filename.jpg)
 * @returns {Promise<boolean>} 삭제 성공 여부
 */
async function deleteFile(webPath) {
  try {
    if (!webPath || typeof webPath !== 'string') {
      return false;
    }

    // 보안: uploads 경로만 삭제 허용
    if (!webPath.startsWith('/uploads/')) {
      console.error('삭제 불가: uploads 외부 경로', webPath);
      return false;
    }

    const filename = path.basename(webPath);
    const fullPath = path.join(UPLOAD_DIR, filename);

    try {
      await fs.access(fullPath);
      await fs.unlink(fullPath);
      return true;
    } catch (accessError) {
      // 파일이 없으면 성공으로 처리
      if (accessError.code === 'ENOENT') {
        return true;
      }
      throw accessError;
    }
  } catch (error) {
    console.error('파일 삭제 실패:', error);
    return false;
  }
}

/**
 * 여러 파일 삭제
 * @param {string[]} webPaths - 웹 경로 배열
 * @returns {Promise<void>}
 */
async function deleteMultipleFiles(webPaths) {
  for (const webPath of webPaths) {
    if (webPath) {
      await deleteFile(webPath);
    }
  }
}

module.exports = {
  saveBase64Image,
  saveMultipleImages,
  deleteFile,
  deleteMultipleFiles,
  UPLOAD_DIR
};
