import fs from 'node:fs';
import path from 'node:path';

const root = 'D:/AIcoding/WishFulfilled/知识库/under-anything';
const wiki = `${root}/wishfulfilled-wiki`;
const reqDir = `${wiki}/05_需求文档`;
const graphPaths = [
  `${wiki}/.understand-anything/knowledge-graph.json`,
  `${root}/wishfulfilled-dashboard/knowledge-graph.json`,
];
const metaPaths = [
  `${wiki}/.understand-anything/meta.json`,
  `${root}/wishfulfilled-dashboard/meta.json`,
];

const files = fs.readdirSync(reqDir)
  .filter((name) => /\.(md|html?)$/i.test(name))
  .sort((a, b) => a.localeCompare(b, 'zh-Hans-CN'));

function readText(filePath) {
  return fs.readFileSync(filePath, 'utf8');
}

function cleanLineNumbers(text) {
  const lines = text.split(/\r?\n/);
  let changed = 0;
  const cleaned = lines.map((line) => {
    const match = line.match(/^\s*\d+\|(.+)$/);
    if (!match) return line;
    changed += 1;
    return match[1];
  });
  return changed >= Math.max(3, Math.floor(lines.length / 4)) ? cleaned.join('\n') : text;
}

function stripHtml(text) {
  return text
    .replace(/<script[\s\S]*?<\/script>|<style[\s\S]*?<\/style>/gi, ' ')
    .replace(/<[^>]+>/g, ' ')
    .replace(/&nbsp;/g, ' ')
    .replace(/&amp;/g, '&')
    .replace(/\s+/g, ' ')
    .trim();
}

function titleFor(fileName, text) {
  if (/\.html?$/i.test(fileName)) {
    const match = text.match(/<title[^>]*>([\s\S]*?)<\/title>/i);
    const title = match ? stripHtml(match[1]) : '';
    if (title) return title;
  }
  for (const line of text.split(/\r?\n/)) {
    const trimmed = line.trim();
    if (trimmed.startsWith('#')) return trimmed.replace(/^#+\s*/, '').trim();
  }
  return path.basename(fileName, path.extname(fileName)).replace(/^\d+[-_]/, '').replace(/_/g, ' ');
}

function summaryFor(fileName, text) {
  const plain = /\.html?$/i.test(fileName)
    ? stripHtml(text)
    : text.replace(/[`*_>#|\-\[\]()]/g, ' ').replace(/\s+/g, ' ').trim();
  return plain ? plain.slice(0, 180) : '需求文档。';
}

function tagsFor(text) {
  const tags = ['05_需求文档', '需求文档'];
  const match = text.match(/^tags:\s*\[(.*?)\]/m);
  if (!match) return tags;
  for (const item of match[1].split(/[,，]/)) {
    const tag = item.trim().replace(/^['"]|['"]$/g, '');
    if (tag && !tags.includes(tag)) tags.push(tag);
  }
  return tags;
}

function complexityFor(text) {
  if (text.length > 20000) return 'complex';
  if (text.length > 5000) return 'moderate';
  return 'simple';
}

function updateGraph(graphPath) {
  const graph = JSON.parse(fs.readFileSync(graphPath, 'utf8'));
  graph.nodes ??= [];
  graph.edges ??= [];
  graph.layers ??= [];

  const byId = new Map(graph.nodes.map((node) => [node.id, node]));
  const edgeKeys = new Set(graph.edges.map((edge) => `${edge.source}|${edge.target}|${edge.type}`));
  let layer = graph.layers.find((item) => item.id === 'layer-requirements');
  if (!layer) {
    layer = {
      id: 'layer-requirements',
      name: '需求文档',
      description: '所有正式需求、业务规则、需求变更和需求索引。',
      nodeIds: ['flow:layer-requirements'],
    };
    graph.layers.push(layer);
  }
  layer.nodeIds ??= [];

  let added = 0;
  let updated = 0;
  for (const fileName of files) {
    const absolutePath = `${reqDir}/${fileName}`;
    const relPath = `05_需求文档/${fileName}`;
    const nodeId = `doc:${relPath.replace(/\.[^.]+$/, '')}`;
    const text = cleanLineNumbers(readText(absolutePath));
    const node = {
      id: nodeId,
      type: 'document',
      name: titleFor(fileName, text),
      filePath: relPath,
      summary: summaryFor(fileName, text),
      tags: tagsFor(text),
      complexity: complexityFor(text),
      knowledgeMeta: {
        content: text,
        wikilinks: [...text.matchAll(/\[\[([^\]]+)\]\]/g)].map((match) => match[1]),
        category: 'layer-requirements',
      },
    };

    if (byId.has(nodeId)) {
      Object.assign(byId.get(nodeId), node);
      updated += 1;
    } else {
      graph.nodes.push(node);
      byId.set(nodeId, node);
      added += 1;
    }

    if (!layer.nodeIds.includes(nodeId)) layer.nodeIds.push(nodeId);
    const edgeKey = `flow:layer-requirements|${nodeId}|documents`;
    if (!edgeKeys.has(edgeKey)) {
      graph.edges.push({
        source: 'flow:layer-requirements',
        target: nodeId,
        type: 'documents',
        direction: 'forward',
        description: '本层文档',
        weight: 0.65,
      });
      edgeKeys.add(edgeKey);
    }
  }

  const count = layer.nodeIds.filter((id) => id !== 'flow:layer-requirements').length;
  const flow = byId.get('flow:layer-requirements');
  if (flow) {
    flow.summary = '所有正式需求、业务规则、需求变更和需求索引。点击本层可查看全部需求文档并检索。';
    flow.knowledgeMeta ??= {};
    flow.knowledgeMeta.content = `# 需求文档\n\n所有正式需求、业务规则、需求变更和需求索引。点击本层可查看全部需求文档并检索。\n\n本层包含 ${count} 个文档。点击右侧 Files 或在本层详情中选择具体文档查看内容。`;
    flow.knowledgeMeta.category = 'layer-requirements';
  }

  graph.project ??= {};
  graph.project.analyzedAt = new Date().toISOString();
  fs.writeFileSync(graphPath, `${JSON.stringify(graph, null, 2)}\n`, 'utf8');
  return { graphPath, added, updated, requirements: count, nodes: graph.nodes.length };
}

const results = graphPaths.map(updateGraph);
for (const metaPath of metaPaths) {
  if (!fs.existsSync(metaPath)) continue;
  const meta = JSON.parse(fs.readFileSync(metaPath, 'utf8'));
  const graph = JSON.parse(fs.readFileSync(`${path.dirname(metaPath)}/knowledge-graph.json`, 'utf8'));
  meta.lastAnalyzedAt = new Date().toISOString();
  meta.analyzedFiles = graph.nodes.filter((node) => String(node.id).startsWith('doc:')).length;
  fs.writeFileSync(metaPath, `${JSON.stringify(meta, null, 2)}\n`, 'utf8');
}

console.log(JSON.stringify(results, null, 2));
