/**
 * LiteMall 自动 SEO 文章生成器
 *
 * 核心职责：
 *  1. 抓取商品标题/规格/描述里的数值（价格/尺寸/重量/材质/容量等）
 *  2. 结合 SEO 关键词（商品 seo_keywords + 用户搜索长尾词）
 *  3. 多模式生成文章（规格测评/问答对话/场景种草/对比分析），内容格式不固定
 *  4. 时间戳注入（利于搜索引擎抓取时效内容）
 *  5. 去 AI 化改写（降低机械感）
 *
 * 依赖：ai-client.js（对接用户自填的 AI API Key），复用 chatWithSkill。
 */

const aiClient = require('./ai-client');
const { get, all, run } = require('../utils/db');

// ============ 数值抓取：从标题/规格/描述提取关键数值 ============
// 返回结构化规格对象 { price, weight, size, material, capacity, tech, ... }
function extractSpecs(product) {
  const specs = {};
  const text = [
    product.name || '',
    product.subtitle || '',
    product.description || '',
    product.brief || '',
    (product.product_params ? (typeof product.product_params === 'string' ? product.product_params : JSON.stringify(product.product_params)) : ''),
  ].join(' ');

  // 价格
  if (product.price) specs.price = Number(product.price).toFixed(2);
  // 重量（g / kg）
  let m = text.match(/(\d+(?:\.\d+)?)\s*(克|g|kg|KG|斤)/);
  if (m) specs.weight = m[1] + m[2];
  // 尺寸（长宽高 / cm / mm）
  m = text.match(/(\d+(?:\.\d+)?)\s*(?:x|×|X)\s*(\d+(?:\.\d+)?)(?:\s*(?:x|×|X)\s*(\d+(?:\.\d+)?))?\s*(cm|mm|厘米|毫米)/);
  if (m) specs.size = m.slice(1, 5).filter(Boolean).join('x') + m[4];
  // 材质
  m = text.match(/(不锈钢|铝合金|纯棉|亚麻|硅胶|玻璃|陶瓷|塑料|ABS|金属|实木|竹|皮革|PU|棉\s*麻|涤纶|尼龙|聚酯纤维|碳纤维)/);
  if (m) specs.material = m[1];
  // 容量
  m = text.match(/(\d+(?:\.\d+)?)\s*(L|升|ml|毫升|mAh|mah|Ah)\b/);
  if (m) specs.capacity = m[1] + m[2];
  // 功率/瓦数
  m = text.match(/(\d+(?:\.\d+)?)\s*(W|瓦|kw|KW)\b/);
  if (m) specs.power = m[1] + m[2];
  // 规格值直接抓取（如 型号:xxx / 颜色:xxx / 版本:xxx）
  m = text.match(/(?:型号|颜色|版本|规格|尺码)[:：]\s*([\w\u4e00-\u9fa5\-\.\/\s]{1,12})/);
  if (m) specs.model = m[1].trim();

  // 从 product_specs 表补充（name -> spec_values）
  try {
    const rows = all('SELECT name, spec_values FROM product_specs WHERE product_id=?', [product.id]);
    for (const r of rows) {
      let vals = [];
      try { vals = JSON.parse(r.spec_values || '[]'); } catch (e) { vals = [r.spec_values]; }
      const v = vals.join(' / ').trim();
      if (!v) continue;
      if (/重|量/.test(r.name)) specs.weight = specs.weight || v;
      else if (/尺寸|规格/.test(r.name)) specs.size = specs.size || v;
      else if (/材质/.test(r.name)) specs.material = specs.material || v;
      else if (/型号/.test(r.name)) specs.model = specs.model || v;
    }
  } catch (e) { /* 表可能不存在 */ }
  return Object.keys(specs).length ? specs : null;
}

// ============ 长尾词：从用户真实搜索词取 top ============
function getLongTailKeywords(limit = 8) {
  try {
    return all('SELECT keyword, count FROM search_keywords WHERE LENGTH(keyword)>=2 AND count>=1 ORDER BY count DESC, id DESC LIMIT ?', [limit])
      .map(r => r.keyword.trim()).filter(Boolean);
  } catch (e) { return []; }
}

// ============ 组装关键词集合 ============
function buildKeywords(product, task) {
  const source = task.keyword_source || 'combo';
  const prodWords = String(product.seo_keywords || '')
    .split(/[,，;；\s]+/).map(s => s.trim()).filter(s => s && s.length > 1);
  const longTail = getLongTailKeywords(8);

  let kw = [];
  if (source === 'product') kw = prodWords;
  else if (source === 'search') kw = longTail;
  else { // combo 默认
    kw = [...prodWords];
    for (const t of longTail) if (!kw.includes(t)) kw.push(t);
  }
  // 兜底：用商品名核心词
  if (!kw.length && product.name) {
    kw.push(product.name);
    if (product.category_name) kw.push(product.category_name);
  }
  return kw.slice(0, 10);
}

// ============ 去 AI 化改写 ============
function deAIfy(text, seed) {
  if (!text) return text;
  const seed2 = seed % 100;
  let t = String(text);
  // 1) 删除 AI 套话/机械连接词
  const clichRe = /(总而言之|综上所述|总的来说|首先|其次|再次|最后|与此同时|值得注意的是|需要注意的是|值得一提的是|众所周知)/g;
  t = t.replace(clichRe, '');
  // 2) 替换高频机械词为口语多变说法
  const replMap = {
    '是一款': ['是', '属于', '算是', '定位是'],
    '非常': ['很', '挺', '特别', '相当', '比较'],
    '很不错': ['挺好', '靠谱', '值得', '不赖'],
    '我们相信': ['个人觉得', '实际体验下来', '按我的看法'],
    '总而言之': ['总的来说'],
    '产品': ['这款', '这个', '它'],
  };
  for (const [k, v] of Object.entries(replMap)) {
    const re = new RegExp(k, 'g');
    const opts = v;
    t = t.split(re).map((seg, i) => i < t.split(re).length - 1 ? seg + opts[(seed2 + i) % opts.length] : seg).join('');
  }
  // 3) 句子节奏打散：长句中间插逗号
  const arr = t.split('。');
  for (let i = 0; i < arr.length; i++) {
    const seg = arr[i];
    if (seg.length > 30 && (i + seed2) % 3 === 0 && !/？|!$/.test(seg)) {
      const idx = Math.floor(seg.length / 2);
      if (idx > 3 && idx < seg.length - 3) arr[i] = seg.slice(0, idx) + '，' + seg.slice(idx);
    }
  }
  t = arr.join('。');
  t = t.replace(/[，。]{2,}/g, '。').replace(/\s{2,}/g, ' ').trim();
  return t;
}

function pick(seed, arr) { return arr[seed % arr.length]; }

// ============ 标题/开头/结尾 组合池（保证内容格式不固定） ============
const TITLES = {
  spec: (p, kw) => pickVariants(p, [
    `{name}实测：规格细节与选购建议`,
    `{name}怎么选？规格、参数一次讲清楚`,
    `拆解{name}：{kw}场景下的配置与表现`,
    `{name}全规格解析，帮你避开选购坑`,
    `入手{name}前，先看懂这些规格参数`,
    `2026版{name}指南：规格、价格与适用人群`,
  ]),
  qa: (p, kw) => pickVariants(p, [
    `关于{name}，你关心的{kw}问题都在这`,
    `{name}常见问题解答：{kw}选购不踩雷`,
    `问：{name}值得买吗？答：看这几个点`,
    `{name}选购问答：规格、参数与真实体验`,
    `{kw}人群必看：{name}全方位答疑`,
    `{name}入门问答，看完再决定`,
  ]),
  scene: (p, kw) => pickVariants(p, [
    `用了{name}一段时间，这些{kw}场景真香`,
    `{name}真实体验：{kw}使用场景分享`,
    `记录我入手{name}的{kw}使用日常`,
    `{name}实测笔记：这些场景最常用`,
    `一个{kw}爱好者的{name}使用分享`,
    `{name}这半年，在不同场景下的表现`,
  ]),
  compare: (p, kw) => pickVariants(p, [
    `{name}对比分析：{kw}场景选哪个更值`,
    `同类怎么选？{name}与{kw}的取舍`,
    `{name}避坑对比：规格与实际差异`,
    `{name}值不值？从规格和价格横向看`,
    `{kw}选购对比：{name}的优势与短板`,
    `多维度对比{name}，优缺点不藏着`,
  ]),
};
function pickVariants(p, arr) {
  const seed = (p.id || 0) + new Date().getDate();
  const tpl = arr[seed % arr.length];
  return tpl
    .replace('{name}', p.name)
    .replace('{kw}', (p.seo_keywords ? String(p.seo_keywords).split(/[,，]/)[0] : '') || '选购');
}

const OPENERS = [
  (p) => `最近不少人在问${p.name}，趁着入手的热乎劲，把几个关心的点捋一捋。`,
  (p) => `要说${p.name}，得先看自己到底需要什么，再谈规格合不合适。`,
  (p) => `身边好几个朋友在纠结${p.name}，这里就结合我的实际体验聊一聊。`,
  (p) => `断断续续用了${p.name}一段时间，聊聊真实感受，不一定适合所有人。`,
  (p) => `写这篇之前，我又把${p.name}的规格翻了一遍，结合用下来体会，尽量客观。`,
];
const CLOSERS = [
  (p) => `总之，按自己的实际场景选，比盯着参数表更重要。希望这篇对你有参考。`,
  (p) => `大概就到这，如果你也在纠结${p.name}，可以按上面几点对照下自己的需求。`,
  (p) => `看再多测评，不如上手试一下。这篇就当个参考，别太较真。`,
  (p) => `先写这么多，后续有新的体会再更新。有问题欢迎交流。`,
];

// ============ 时间戳注入 ============
function injectTimestamp(text, seed) {
  const months = ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'];
  const now = new Date();
  const month = months[now.getMonth()];
  const day = now.getDate();
  // 随机+自然地在首段/中段/结尾插入时效语（不固定位置）
  const phrases = [
    `最近（${month}）`,
    `写于${now.getFullYear()}年${month}`,
    `近段时间`,
    `这阵子`,
    `更新于${month}${day}日`,
  ];
  const ph = phrases[(now.getDate() + seed) % phrases.length];
  // 在第一个"。"之后插入一句时效起手语
  const idx = text.indexOf('。');
  if (idx > 0 && idx < 80) {
    return text.slice(0, idx + 1) + '\n\n' + ph + '，' + text.slice(idx + 1).trim();
  }
  return text;
}

// ============ Prompt 组装 ============
function buildPrompt(mode, product, specs, keywords) {
  const kw = keywords.slice(0, 5).join('、');
  const specStr = specs ? Object.entries(specs).map(([k, v]) => `${k}:${v}`).join('；') : '无明确规格数值';
  const cat = product.category_name || '未分类';
  const price = product.price ? `¥${product.price}` : '未标价';

  const ctx = `商品名称：${product.name}\n商品分类：${cat}\n商品价格：${price}\n商品简介：${product.subtitle || ''}\n核心规格数值：${specStr}\n商品描述：${String(product.description || product.brief || '').slice(0, 300)}\nSEO关键词：${kw}`;

  const baseReq = `
要求：
1. 语言自然口语化，像真实用户在分享，不要明显AI腔
2. 围绕商品规格数值展开，别凭空编造
3. 适当融入关键词和长尾词，但不要生硬堆砌
4. 全文300-600字左右，分成3-5个自然段
5. 不要使用markdown语法符号（##、**等）
6. 不要出现"总而言之、综上所述、首先其次"这类AI套话
7. 结尾给一句时效性收尾（提及近期/本月即可）
不用输出标题，正文即可。`;

  switch (mode) {
    case 'qa':
      return `${ctx}\n\n请以「问答对话形式」生成一篇商品介绍文章：围绕用户最关心的3-4个问题（如值不值得买、规格参数怎么理解、适合什么场景、和同类的区别）展开，"问"和"答"交替。\n${baseReq}`;
    case 'scene':
      return `${ctx}\n\n请以「真实使用场景分享」风格生成：从某个具体生活/使用场景切入，讲述围绕该商品的真实体验与感受（可含我口吻叙述），让读者有代入感。\n${baseReq}`;
    case 'compare':
      return `${ctx}\n\n请以「对比分析型」生成：站在选购者角度，把该商品的规格、价格、适用场景与同类/不同定位做横向对比，给出取舍建议，语气中立。\n${baseReq}`;
    case 'spec':
    default:
      return `${ctx}\n\n请以「商品规格解析与选购指南」风格生成：把规格数值讲透，说清楚每个参数对日常使用意味着什么，并用选购建议收尾。\n${baseReq}`;
  }
}

// ============ 主入口：生成一篇 SEO 文章 ============
/**
 * @param {object} product 商品对象
 * @param {object} task 任务配置
 * @returns {Promise<{title, summary, content, mode, keywords}>}
 */
async function generateArticle(product, task) {
  const mode = (task.mode === 'random') ? pickRandomMode(product.id) : (task.mode || 'spec');
  const specs = extractSpecs(product);
  const keywords = buildKeywords(product, task);
  const prompt = buildPrompt(mode, product, specs, keywords);
  const seed = (product.id || 1) + new Date().getDate();

  const content = await aiClient.chatWithSkill('product_seo', [{ role: 'user', content: prompt }], {
    temperature: 0.85,
    max_tokens: 1500,
    context: { product_name: product.name, mode },
  });

  // 去 AI 化 + 时间戳
  let articleBody = deAIfy(content, seed);
  articleBody = injectTimestamp(articleBody, seed);

  // 标题与摘要
  const title = (TITLES[mode] || TITLES.spec)(product, keywords).slice(0, 60);
  const summary = extractSummary(articleBody, seed);

  return { title, summary, content: articleBody, mode, keywords, specs };
}

function pickRandomMode(pid) {
  const modes = ['spec', 'qa', 'scene', 'compare'];
  return modes[(pid + new Date().getDate()) % modes.length];
}
function extractSummary(text, seed) {
  const arr = text.split(/[。\n]/).filter(s => s.trim().length > 12 && s.trim().length < 80);
  if (!arr.length) return (text || '').slice(0, 60);
  return arr[seed % arr.length].replace(/\s+/g, ' ').trim().slice(0, 70);
}

module.exports = {
  extractSpecs,
  getLongTailKeywords,
  buildKeywords,
  deAIfy,
  generateArticle,
  pickRandomMode,
};
