/**
 * 光湖视频AI系统 · 图片API适配层
 * D135 · 铸渊 ICE-GL-ZY001
 *
 * 基于 火山方舟 Seedream 4.0 API
 * 文档: https://www.volcengine.com/docs/82379/1541523
 *
 * 用途: 为视频生成器的「参考图模式」提供角色标准人设图
 *       同一套 API Key，同一个 BASE_URL，图片和视频共享计费
 *
 * 使用方式:
 *   const { generateImage } = require('./image-api-adapter');
 *   const result = await generateImage({ prompt: '...', size: '2K' });
 *
 * 输出路径优先级 (与视频一致):
 *   1. opts.outputPath（显式指定）
 *   2. 外接硬盘 JZAO /Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片/
 *   3. 本地 fallback video-ai-system/outputs/images/
 *
 * 环境变量（复用 video-ai-system/.env）:
 *   JIMENG_API_KEY=xxx       火山方舟 API Key (与视频共享)
 *   JIMENG_BASE_URL=https://ark.cn-beijing.volces.com/api/v3
 */

const fs = require('fs');
const path = require('path');
const https = require('https');
const http = require('http');
const { loadVideoAiEnv } = require('./env-loader');

// ==================== 环境变量 ====================
loadVideoAiEnv(path.resolve(__dirname, '../.env'));

const API_KEY = process.env.JIMENG_API_KEY || '';
const BASE_URL = process.env.JIMENG_BASE_URL || 'https://ark.cn-beijing.volces.com/api/v3';
const IMAGE_MODEL = 'doubao-seedream-4-0-250828';

// ==================== 输出路径 ====================
const JZAO_IMAGE_ROOT = '/Volumes/JZAO/铸渊-ICE-GL-ZY001/OUT-输出/图片';
const LOCAL_IMAGE_ROOT = path.resolve(__dirname, '../outputs/images');
const IMAGE_OUTPUT_ROOT = (() => {
  if (fs.existsSync(JZAO_IMAGE_ROOT)) return JZAO_IMAGE_ROOT;
  return LOCAL_IMAGE_ROOT;
})();

// ==================== API 规范 ====================
const IMAGE_API_SPEC = {
  model: { values: [IMAGE_MODEL], default: IMAGE_MODEL },
  size: {
    presets: ['2K', '4K'],
    specific: ['2048x2048', '2304x1728', '1728x2304', '2560x1440', '1440x2560', '2496x1664', '1664x2496', '3024x1296'],
    default: '2048x2048',
    description: '2K/4K 或具体像素值，总像素 921600~16777216',
  },
  promptMaxLen: { chinese: 300, english: 600 },
  responseFormat: { values: ['url', 'b64_json'], default: 'url' },
};

// ==================== HTTP 工具（与 video-api-adapter 同款，独立以避免循环依赖） ====================

async function httpPost(url, body, apiKey) {
  const urlObj = new URL(url);
  const isHttps = urlObj.protocol === 'https:';
  const transport = isHttps ? https : http;
  const payload = JSON.stringify(body);

  return new Promise((resolve, reject) => {
    const req = transport.request(url, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${apiKey}`,
        'Content-Type': 'application/json',
        'Content-Length': Buffer.byteLength(payload),
      },
      timeout: 60000,
    }, (res) => {
      let data = '';
      res.on('data', chunk => data += chunk);
      res.on('end', () => {
        try {
          const json = JSON.parse(data);
          if (res.statusCode >= 400) {
            reject(new Error(`API错误(${res.statusCode}): ${json.error?.message || json.message || '未知'}`));
            return;
          }
          resolve(json);
        } catch (e) {
          reject(new Error(`JSON解析失败: ${data.substring(0, 200)}`));
        }
      });
    });
    req.on('error', reject);
    req.on('timeout', () => { req.destroy(); reject(new Error('请求超时')); });
    req.write(payload);
    req.end();
  });
}

async function downloadImage(imageUrl, outputPath) {
  const urlObj = new URL(imageUrl);
  const isHttps = urlObj.protocol === 'https:';
  const transport = isHttps ? https : http;

  return new Promise((resolve, reject) => {
    const dir = path.dirname(outputPath);
    if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });

    const file = fs.createWriteStream(outputPath);
    transport.get(imageUrl, (res) => {
      if (res.statusCode >= 300 && res.statusCode < 400 && res.headers.location) {
        const redirectUrl = res.headers.location.startsWith('http')
          ? res.headers.location
          : `${urlObj.protocol}//${urlObj.host}${res.headers.location}`;
        downloadImage(redirectUrl, outputPath).then(resolve).catch(reject);
        return;
      }
      res.pipe(file);
      file.on('finish', () => { file.close(); resolve(outputPath); });
      file.on('error', (err) => { try { fs.unlinkSync(outputPath); } catch (_) {} reject(err); });
    }).on('error', reject);
  });
}

function resolveImagePath(filename) {
  const dir = IMAGE_OUTPUT_ROOT;
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
  return path.join(dir, filename);
}

// ==================== 预校验 ====================

/**
 * 图片参数预校验
 */
function preflightImageCheck({ prompt, size }) {
  const warnings = [];
  const errors = [];
  const corrected = {};

  if (!prompt || !prompt.trim()) {
    errors.push('提示词不能为空');
  } else {
    const chineseChars = (prompt.match(/[\u4e00-\u9fff]/g) || []).length;
    if (chineseChars > IMAGE_API_SPEC.promptMaxLen.chinese) {
      warnings.push(`提示词 ${chineseChars} 字，超过建议 ${IMAGE_API_SPEC.promptMaxLen.chinese} 字`);
    }
  }

  if (size) {
    const s = String(size);
    if (IMAGE_API_SPEC.size.presets.includes(s) || IMAGE_API_SPEC.size.specific.includes(s)) {
      corrected.size = s;
    } else {
      warnings.push(`size "${size}" 不在支持列表中，使用默认 ${IMAGE_API_SPEC.size.default}`);
      corrected.size = IMAGE_API_SPEC.size.default;
    }
  } else {
    corrected.size = IMAGE_API_SPEC.size.default;
  }

  return { valid: errors.length === 0, warnings, errors, corrected };
}

// ==================== 生成图片 ====================

/**
 * 生成图片（同步接口，无需轮询）
 * @param {string} opts.prompt - 提示词
 * @param {string} [opts.size] - 尺寸，默认 2048x2048
 * @param {string} [opts.outputPath] - 输出路径
 * @param {string} [opts.filename] - 文件名（如 char-003-subai-ref.png）
 * @returns {Promise<{imagePath: string, imageUrl: string, size: string, usage: object}>}
 */
async function generateImage({ prompt, size, outputPath, filename }) {
  if (!API_KEY) {
    throw new Error('未配置 JIMENG_API_KEY');
  }

  const preflight = preflightImageCheck({ prompt, size });
  if (!preflight.valid) {
    console.error('[ImageAPI·预校验] ❌', preflight.errors.join('; '));
    throw new Error(`预校验失败: ${preflight.errors.join('; ')}`);
  }
  if (preflight.warnings.length > 0) {
    console.warn('[ImageAPI·预校验] ⚠️', preflight.warnings.join('; '));
  }

  const finalSize = preflight.corrected.size;

  console.log(`[ImageAPI] 提交文生图: ${prompt.substring(0, 60)}...`);

  const payload = {
    model: IMAGE_MODEL,
    prompt: prompt.trim(),
    size: finalSize,
    response_format: 'url',
    watermark: false,
  };

  const data = await httpPost(`${BASE_URL}/images/generations`, payload, API_KEY);

  const imageUrl = data.data?.[0]?.url || data.url || data.data?.[0]?.b64_json;
  if (!imageUrl) {
    throw new Error(`API未返回图片URL: ${JSON.stringify(data).substring(0, 200)}`);
  }

  const finalPath = outputPath || resolveImagePath(filename || `image-${Date.now()}.png`);

  console.log(`[ImageAPI] 生成完成，下载到: ${finalPath}`);
  await downloadImage(imageUrl, finalPath);

  const usage = data.usage || {};
  console.log(`[ImageAPI] ✅ 已保存: ${finalPath}  消耗: ${usage.total_tokens || '?'} tokens`);

  return {
    imagePath: finalPath,
    imageUrl,
    size: finalSize,
    usage,
  };
}

// ==================== 角色参考图 ====================

/**
 * 生成角色标准人设图（用于视频参考图模式）
 * @param {string} charId - 角色编号，如 'CHAR-003'
 * @param {object} l0Descriptor - L0底层编码描述
 * @param {object} l1Config - L1服装配置
 * @returns {Promise<{imagePath: string, charId: string}>}
 */
async function generateCharacterRef({ charId, l0Descriptor, l1Config }) {
  const prompt = [
    l0Descriptor,
    l1Config?.clothing || '',
    '正面胸像，面部清晰可见，中性表情，均匀自然光，纯色灰色背景，高质量，3D动画渲染，中国风仙侠动态漫，亚洲面孔'
  ].filter(Boolean).join('，');

  const filename = `${charId.toLowerCase()}-ref-portrait.png`;

  console.log(`[ImageAPI·角色参考图] 生成 ${charId} 人设图...`);

  const result = await generateImage({
    prompt,
    size: '1728x2304',  // 3:4 竖屏胸像
    filename,
  });

  // 注册索引
  const registryPath = path.resolve(__dirname, '../outputs/image-registry.json');
  let registry = { _meta: { updated: new Date().toISOString() }, chars: {} };
  try {
    if (fs.existsSync(registryPath)) registry = JSON.parse(fs.readFileSync(registryPath, 'utf-8'));
  } catch (_) {}
  registry.chars[charId] = {
    charId,
    imagePath: result.imagePath,
    prompt: prompt.substring(0, 120),
    size: result.size,
    generatedAt: new Date().toISOString(),
  };
  registry._meta.updated = new Date().toISOString();
  const dir = path.dirname(registryPath);
  if (!fs.existsSync(dir)) fs.mkdirSync(dir, { recursive: true });
  fs.writeFileSync(registryPath, JSON.stringify(registry, null, 2), 'utf-8');

  return { imagePath: result.imagePath, charId };
}

module.exports = {
  generateImage,
  generateCharacterRef,
  preflightImageCheck,
  downloadImage,
  resolveImagePath,
  IMAGE_MODEL,
  IMAGE_OUTPUT_ROOT,
  IMAGE_API_SPEC,
};
