'use strict';
// Clover 图片质量测试 · codeproxy 调用核心
// 复用自 xhs-tool/backend/infrastructure/aiClient.js（已实测跑通的对的路），简化：去降级、去sharp
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '.env') });
const FormData = require('form-data');
const https = require('https');
const fs = require('fs');

const KEY = process.env.AI_API_KEY;
const BASE_URL = process.env.AI_BASE_URL;
const MODEL_IMAGE = process.env.MODEL_IMAGE || 'gpt-image-2';
const IMAGE_TIMEOUT = 300000;

if (!KEY) throw new Error('AI_API_KEY 未配置（见 test/.env）');

const sleep = ms => new Promise(r => setTimeout(r, ms));

function toBuffer(img) {
  if (Buffer.isBuffer(img)) return img;
  if (typeof img === 'string' && img.startsWith('data:'))
    return Buffer.from(img.replace(/^data:[^;]+;base64,/, ''), 'base64');
  return fs.readFileSync(img); // 本地文件路径
}

// 单次请求：POST /images/edits (multipart)
function postEditOnce({ imgList, prompt, m, sz }) {
  const form = new FormData();
  form.append('model', m);
  form.append('prompt', prompt);
  form.append('size', sz);
  form.append('n', '1');
  for (let i = 0; i < imgList.length; i++) {
    const buf = toBuffer(imgList[i]);
    form.append('image[]', buf, { filename: `img_${i}.jpg`, contentType: 'image/jpeg' });
  }
  return new Promise((resolve, reject) => {
    const ac = new AbortController();
    const timer = setTimeout(() => { ac.abort(); req.destroy(new Error('300s timeout')); }, IMAGE_TIMEOUT);
    const req = https.request(`${BASE_URL}/images/edits`, {
      method: 'POST',
      headers: { ...form.getHeaders(), Authorization: `Bearer ${KEY}` },
      signal: ac.signal,
    }, (r) => {
      let body = '';
      r.on('data', d => body += d);
      r.on('end', () => { clearTimeout(timer); resolve({ status: r.statusCode, body }); });
      r.on('error', reject);
    });
    req.on('error', (e) => { clearTimeout(timer); reject(e); });
    form.pipe(req);
  });
}

// 可重试错误：上游/网关临时故障 + 限流 + 超时
const RETRYABLE = new Set([429, 500, 502, 503, 504]);

// 带参考图出图：失败自动退避重试（复用 xhs-tool 的重试思路）
async function imageEdit({ images, prompt, traceId = 't', model, size, maxRetry = 3 }) {
  const m = model || MODEL_IMAGE;
  const sz = size || process.env.IMAGE_SIZE || '1024x1536';
  const imgList = Array.isArray(images) ? images : [images];
  let lastErr;
  for (let attempt = 1; attempt <= maxRetry; attempt++) {
    const t0 = Date.now();
    try {
      const res = await postEditOnce({ imgList, prompt, m, sz });
      console.log(`[imageEdit][${traceId}] try=${attempt}/${maxRetry} model=${m} size=${sz} imgs=${imgList.length} status=${res.status} ms=${Date.now()-t0}`);
      if (res.status === 200) {
        const d = JSON.parse(res.body).data[0];
        if (d.url) return { type: 'url', value: d.url };
        if (d.b64_json) return { type: 'b64', value: d.b64_json };
        throw new Error('返回既无 url 也无 b64_json');
      }
      lastErr = new Error(`HTTP ${res.status}: ${res.body.slice(0, 300)}`);
      if (!RETRYABLE.has(res.status)) throw lastErr; // 401/404等不重试，直接抛
    } catch (e) {
      lastErr = e;
      const code = (e.message.match(/HTTP (\d+)/) || [])[1];
      if (code && !RETRYABLE.has(Number(code))) throw e;
    }
    if (attempt < maxRetry) {
      const wait = 3000 * attempt; // 3s,6s 退避
      console.log(`  ↻ 上游临时故障，${wait/1000}s 后重试…`);
      await sleep(wait);
    }
  }
  throw lastErr;
}

// 保存结果到文件（url则下载，b64则解码）
async function saveResult(result, outPath) {
  if (result.type === 'b64') {
    fs.writeFileSync(outPath, Buffer.from(result.value, 'base64'));
    return outPath;
  }
  // url：下载
  await new Promise((resolve, reject) => {
    https.get(result.value, (r) => {
      const chunks = [];
      r.on('data', c => chunks.push(c));
      r.on('end', () => { fs.writeFileSync(outPath, Buffer.concat(chunks)); resolve(); });
      r.on('error', reject);
    }).on('error', reject);
  });
  return outPath;
}

module.exports = { imageEdit, saveResult, toBuffer, sleep };
