/**
 * 图片迁移工具
 * 用于在数据搬家时自动下载/打包商品图片
 */

const fs = require('fs');
const path = require('path');
const https = require('https');
const http = require('http');

const UPLOADS_DIR = path.resolve(__dirname, '..', '..', '..', 'uploads');
const MIGRATION_IMG_DIR = path.join(UPLOADS_DIR, 'migration');

// 确保迁移图片目录存在
function ensureDirs() {
  if (!fs.existsSync(MIGRATION_IMG_DIR)) {
    fs.mkdirSync(MIGRATION_IMG_DIR, { recursive: true });
  }
}

/**
 * 🔒 SSRF防护：判断URL是否可安全下载。
 * 拒绝非http(s)、拒绝指向内网/保留IP的域名（防访问云元数据/内网服务）
 */
function isSafeDownloadUrl(url) {
  try {
    const u = new URL(url);
    if (u.protocol !== 'http:' && u.protocol !== 'https:') return false;
    const host = u.hostname;
    // 拒绝裸IP段与常见内网域名
    if (/^(\d{1,3}\.){3}\d{1,3}$/.test(host)) {
      const parts = host.split('.').map(Number);
      if (parts.length !== 4) return false;
      const [a, b] = parts;
      if (a === 0 || a === 10 || a === 127) return false;
      if (a === 192 && b === 168) return false;
      if (a === 172 && b >= 16 && b <= 31) return false;
      if (a === 169 && b === 254) return false; // 云元数据
      if (a >= 224) return false; // 组播/保留
      return true;
    }
    // 本地主机名
    if (host === 'localhost' || host === '::1') return false;
    // 解析域名，检查是否有内网解析结果（DNS rebinding 基础防护）
    const dns = require('dns');
    const addrs = dns.lookupSync(host, { all: true });
    for (const a of addrs) {
      const ip = String(a.address || '');
      if (ip.startsWith('10.') || ip.startsWith('127.') || ip.startsWith('192.168.') || ip.startsWith('169.254.')) return false;
      if (/^172\.(1[6-9]|2\d|3[01])\./.test(ip)) return false;
      if (ip === '::1' || ip.startsWith('fc') || ip.startsWith('fe80')) return false;
    }
    return true;
  } catch (e) {
    return false;
  }
}

/**
 * 从URL下载图片
 * @param {string} url - 图片下载地址
 * @param {string} productId - 商品ID（用于子目录命名）
 * @returns {string|null} 本地相对路径
 */
function downloadImage(url, productId) {
  if (!url || typeof url !== 'string') return null;
  
  // 清理URL
  url = url.trim();
  if (!url.startsWith('http://') && !url.startsWith('https://')) {
    // 可能是相对路径，跳过（没有baseUrl时无法下载）
    return null;
  }
  
  // 🔒 SSRF 防护：拒绝内网/保留地址，防止被引导访问云元数据/内网
  if (!isSafeDownloadUrl(url)) {
    console.error('[迁移-图片] 拦截不安全URL:', url.slice(0, 80));
    return null;
  }
  
  try {
    ensureDirs();
    
    // 生成文件名
    const ext = path.extname(url.split('?')[0]) || '.jpg';
    const safeName = Date.now() + '_' + Math.random().toString(36).slice(2, 8) + ext;
    const subDir = productId ? String(productId) : 'common';
    const dirPath = path.join(MIGRATION_IMG_DIR, subDir);
    
    if (!fs.existsSync(dirPath)) {
      fs.mkdirSync(dirPath, { recursive: true });
    }
    
    const filePath = path.join(dirPath, safeName);
    
    // 下载
    const mod = url.startsWith('https') ? https : http;
    
    return new Promise((resolve) => {
      const req = mod.get(url, { 
        timeout: 10000, 
        headers: { 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36' }
      }, (res) => {
        // 检查是否成功
        if (res.statusCode !== 200) {
          resolve(null);
          return;
        }
        
        // 检查是否是图片
        const contentType = res.headers['content-type'] || '';
        if (!contentType.startsWith('image/')) {
          resolve(null);
          return;
        }
        
        const chunks = [];
        let size = 0;
        
        res.on('data', (chunk) => {
          chunks.push(chunk);
          size += chunk.length;
          // 限制单张图片大小（10MB）
          if (size > 10 * 1024 * 1024) {
            req.destroy();
            resolve(null);
          }
        });
        
        res.on('end', () => {
          if (size === 0) { resolve(null); return; }
          fs.writeFileSync(filePath, Buffer.concat(chunks));
          // 返回相对路径
          const relPath = `/uploads/migration/${subDir}/${safeName}`;
          resolve(relPath);
        });
      });
      
      req.on('error', () => resolve(null));
      req.on('timeout', () => { req.destroy(); resolve(null); });
    });
  } catch (err) {
    console.error('[迁移-图片] 下载失败:', url.slice(0, 60), err.message);
    return null;
  }
}

/**
 * 批量下载商品图片
 * @param {Array} products - 商品列表
 * @param {Object} options 
 * @param {string} options.imageBaseUrl - 原站点域名（用于拼接相对路径）
 * @returns {Object} { downloaded, failed, results }
 */
async function downloadProductImages(products, options = {}) {
  const { imageBaseUrl = '' } = options;
  const results = [];
  let downloaded = 0;
  let failed = 0;
  
  for (const product of products) {
    if (!product.id && !product.name) continue;
    
    const productId = product.id || 'unknown';
    const updates = {};
    
    // 处理主图
    if (product.image) {
      const fullUrl = resolveImageUrl(product.image, imageBaseUrl);
      const localPath = await downloadImage(fullUrl, productId);
      if (localPath) {
        updates.image = localPath;
        downloaded++;
        results.push({ product: product.name || productId, field: 'image', from: product.image, to: localPath });
      } else {
        failed++;
      }
    }
    
    // 处理轮播图（兼容JSON数组和逗号分隔两种格式）
    if (product.images) {
      let imgList = [];
      try { imgList = JSON.parse(product.images); } catch(e) { imgList = String(product.images).split(',').filter(Boolean); }
      if (!Array.isArray(imgList)) imgList = [String(product.images)];
      
      const localImages = [];
      for (const imgUrl of imgList) {
        if (!imgUrl || !imgUrl.trim()) continue;
        const fullUrl = resolveImageUrl(imgUrl.trim(), imageBaseUrl);
        const localPath = await downloadImage(fullUrl, productId);
        if (localPath) {
          localImages.push(localPath);
          downloaded++;
        } else {
          failed++;
        }
      }
      if (localImages.length > 0) {
        updates.images = JSON.stringify(localImages);
      }
    }
    
    // 处理详情描述中的富文本图片
    if (product.description) {
      const imgRegex = /<img[^>]+src=["']([^"']+)["'][^>]*>/gi;
      let match;
      const descImgUrls = [];
      while ((match = imgRegex.exec(product.description)) !== null) {
        descImgUrls.push(match[1]);
      }
      
      if (descImgUrls.length > 0) {
        let updatedDesc = product.description;
        for (const imgUrl of descImgUrls) {
          const fullUrl = resolveImageUrl(imgUrl.trim(), imageBaseUrl);
          const localPath = await downloadImage(fullUrl, productId);
          if (localPath) {
            updatedDesc = updatedDesc.replace(imgUrl, localPath);
            downloaded++;
          } else {
            failed++;
          }
        }
        if (updatedDesc !== product.description) {
          updates.description = updatedDesc;
        }
      }
    }
    
    // 更新商品对象
    Object.assign(product, updates);
    
    // 略等避免请求太快被封
    await new Promise(r => setTimeout(r, 100));
  }
  
  return { downloaded, failed, results };
}

/**
 * 解析图片URL（支持相对路径和完整URL）
 */
function resolveImageUrl(imagePath, baseUrl) {
  if (!imagePath) return '';
  imagePath = imagePath.trim();
  
  // 已经是完整URL
  if (imagePath.startsWith('http://') || imagePath.startsWith('https://')) {
    return imagePath;
  }
  
  // 相对路径，拼接baseUrl
  if (baseUrl) {
    const base = baseUrl.replace(/\/+$/, '');
    const img = imagePath.startsWith('/') ? imagePath : '/' + imagePath;
    return base + img;
  }
  
  return imagePath; // 没有baseUrl时保持原值
}

/**
 * 获取CRMEB图片路径（处理其特有的路径格式）
 */
function resolveCrmeBImagePath(imagePath) {
  if (!imagePath) return '';
  imagePath = imagePath.trim();
  
  // CRMEB图片路径格式多样：
  // 1. 完整URL: https://xxx.com/uploads/2026/01/xxx.jpg
  // 2. 相对路径: /uploads/2026/01/xxx.jpg
  // 3. 系统路径: /www/wwwroot/xxx/public/uploads/2026/01/xxx.jpg
  // 4. 数据库路径: uploads/2026/01/xxx.jpg
  
  // 如果是系统绝对路径，尝试转为相对
  if (imagePath.includes('/www/') || imagePath.startsWith('/')) {
    // 尝试提取 uploads 之后的部分
    const match = imagePath.match(/(\/uploads\/.*)$/);
    if (match) return match[1];
  }
  
  return imagePath;
}

/**
 * 将导出包中的图片路径转为可下载的URL
 * @param {Array} products - 商品列表
 * @param {string} baseUrl - 原站点域名
 */
function prepareImageUrls(products, baseUrl) {
  for (const product of products) {
    if (product.image && !product.image.startsWith('http')) {
      product._originalImage = product.image;
      product.image = resolveImageUrl(product.image, baseUrl);
    }
    if (product.images && !product.images.startsWith('http')) {
      product._originalImages = product.images;
      const urls = product.images.split(',').filter(Boolean);
      product.images = urls.map(u => resolveImageUrl(u, baseUrl)).join(',');
    }
  }
}

module.exports = {
  downloadImage,
  downloadProductImages,
  resolveImageUrl,
  resolveCrmeBImagePath,
  prepareImageUrls,
  UPLOADS_DIR,
  MIGRATION_IMG_DIR,
};
