import path from 'node:path';
import { collectScanTargets, exists, read, rel } from './contract-scan-core.mjs';
import { loadIconsSummary } from './tfds-spec-core.mjs';

function buildIconNames(iconsSummary) {
  const names = new Set();
  if (!iconsSummary) return names;
  for (const item of [...(iconsSummary.imCommon || []), ...(iconsSummary.entries || [])]) {
    if (item.name) names.add(String(item.name).toLowerCase());
  }
  return names;
}

function collectIconHits(text, validNames) {
  if (!validNames.size) return [];
  const hits = [];
  for (const m of text.matchAll(/<Icon\b[^>]*\bname\s*=\s*["']([^"']+)["']/gi)) {
    const raw = m[1].trim();
    const name = raw.toLowerCase();
    if (!validNames.has(name)) hits.push(`<Icon name="${raw}" />`);
    if (hits.length >= 8) break;
  }
  return hits;
}

function collectPackageMixHits(text) {
  const hits = [];
  if (/@tfdesign\/b-end\b/.test(text)) hits.push('@tfdesign/b-end');
  if (/@tfdesign\/c-voip-end\b|VoiceToolbar|VoipSmartPagePattern/i.test(text)) {
    hits.push('VoIP 包组件/导入');
  }
  if (/<(?:Table|NavBar|Filter|FormTitle)\b/.test(text)) hits.push('B端后台组件标签');
  if (/\bmax-w-screen|\bmin-w-\[1200/.test(text)) hits.push('桌面宽屏布局类名');
  return [...new Set(hits)].slice(0, 8);
}

function collectRemoteMediaHits(text) {
  const hits = [];
  const patterns = [
    /<(?:Avatar|Bubble|img)\b[^>]*\bsrc\s*=\s*["']https?:\/\/[^"']+["'][^>]*>/gi,
    /\b(?:avatarSrc|avatarUrl|profileImage)\s*:\s*["']https?:\/\/[^"']+["']/gi,
    /pravatar|unsplash|placeholder\.com/i,
  ];
  for (const re of patterns) hits.push(...(text.match(re) || []).slice(0, 4));
  return [...new Set(hits)].slice(0, 8);
}

function collectHandRolledImHits(text) {
  const hits = [];
  if (!/<Bubble\b/.test(text) && /(气泡|bubble)/i.test(text) && /<div\b[^>]*rounded/i.test(text)) {
    hits.push('疑似手搓气泡容器');
  }
  if (!/<Input\b/.test(text) && /(输入框|chat.?input)/i.test(text) && /<textarea\b|<input\b/i.test(text)) {
    hits.push('疑似原生 input/textarea 替代 Input');
  }
  return hits;
}

/**
 * @param {object} opts
 * @param {string} opts.projectRoot
 * @param {string} opts.skillDir
 */
export function runCEndContract({ projectRoot, skillDir }) {
  const issues = [];
  const ok = [];
  const pkgPath = path.join(projectRoot, 'package.json');

  if (!exists(pkgPath)) {
    issues.push(`未找到 package.json（当前检测根目录：${projectRoot}）。`);
    return { issues, ok };
  }

  const iconsSummary = loadIconsSummary(skillDir);
  const validIconNames = buildIconNames(iconsSummary);
  if (validIconNames.size) ok.push(`已加载 icons.summary（${validIconNames.size} 个合法 name）`);

  const { scanRoots, targets } = collectScanTargets(projectRoot);
  if (scanRoots.length === 0) {
    issues.push('未找到可扫描的源码目录，跳过规则扫描。');
    return { issues, ok };
  }
  ok.push(`将扫描：${scanRoots.map((r) => rel(projectRoot, r)).join(', ')}`);

  const hit = new Map();
  for (const f of targets) {
    const t = read(f);
    if (!t) continue;
    const icon = collectIconHits(t, validIconNames);
    const pkgMix = collectPackageMixHits(t);
    const remote = collectRemoteMediaHits(t);
    const handRolled = collectHandRolledImHits(t);
    if (icon.length || pkgMix.length || remote.length || handRolled.length) {
      hit.set(f, { icon, pkgMix, remote, handRolled });
    }
  }

  if (hit.size === 0) {
    ok.push('未发现明显的 C端 IM 误用信号（启发式）');
    return { issues, ok };
  }

  for (const [f, v] of hit.entries()) {
    if (v.pkgMix.length) {
      issues.push(`[${rel(projectRoot, f)}] 包/组件边界疑似错误：${v.pkgMix.join(', ')}。C端 IM 仅用 @tfdesign/c-end；语音页改 c-voip-end；禁止 B端 Table/NavBar/Filter。`);
    }
    if (v.icon.length) {
      issues.push(`[${rel(projectRoot, f)}] Icon name 不在 icons.summary：${v.icon.join(', ')}。先执行 tfds-im icons <关键词>。`);
    }
    if (v.remote.length) {
      issues.push(`[${rel(projectRoot, f)}] 疑似外链头像/占位图：${v.remote.join(', ')}。须用包内 Avatar/Background。`);
    }
    if (v.handRolled.length) {
      issues.push(`[${rel(projectRoot, f)}] ${v.handRolled.join('；')}。应使用 Bubble / Input 组件。`);
    }
  }

  issues.push('建议：生成前执行 `npx tfds-im spec <id>` 读取 props/rules。');
  return { issues, ok };
}
