import fs from 'node:fs';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { FIELD_ANNOTATION_SPEC } from './field-annotation-spec.mjs';

const __dirname = path.dirname(fileURLToPath(import.meta.url));
const protoRoot = path.resolve(__dirname, '..');
const prdPath = path.join(protoRoot, '.spec/requirements-prd.md');
const sourcePath = path.join(protoRoot, 'annotation-source.json');
const columnsPath = path.join(protoRoot, 'components/tableColumns.ts');
const tipsPath = path.join(protoRoot, 'columnHeaderTips.ts');

const legacyPrd = fs.existsSync(prdPath) ? fs.readFileSync(prdPath, 'utf8') : '';
const existing = fs.existsSync(sourcePath)
  ? JSON.parse(fs.readFileSync(sourcePath, 'utf8'))
  : null;

/** 保留批注工具里已写入的 markdown，避免被 PRD 摘要覆盖 */
const markdownMap = { ...(existing?.markdownMap ?? {}) };
delete markdownMap['lbl-btn-mark-confirmed'];
delete markdownMap['lbl-btn-add-row'];
markdownMap['lbl-col-status'] = [
  '## 收款状态',
  '',
  '当收款记录中分配金额完全覆盖账单的应收金额时，显示**已收款**。',
  '当收款记录中分配金额≤账单的应收金额时，显示**部分收款**。',
  '未分配收款记录时，显示为**未收款**。其他状态去除。',
  '',
  '---',
].join('\n');
markdownMap['lbl-filter'] = [
  '## 2. 筛选区',
  '',
  '默认展示 4 项（一行），点击「更多筛选」展开全部 8 项。',
  '',
  '| 筛选项 | 说明 |',
  '|---|---|',
  '| 年份 / 月份 | 账单所属年月 |',
  '| 业务部门 / 业务员 | 精确匹配 |',
  '| 车牌号码 | 精确匹配 |',
  '| 客户名称 | 模糊包含 |',
  '| 明细状态 | 未收款 / 部分收款 / 已收款 |',
  '| 应付款日 | 单输入框双日历区间，精确至日 |',
  '',
  '---',
].join('\n');
markdownMap['lbl-toolbar'] = [
  '## 4. 列表工具栏',
  '',
  '左侧「仅显示未收款数据」勾选后，列表仅显示状态不等于已收款的记录。',
  '',
  '| 按钮 | 行为 |',
  '|---|---|',
  '| 批量导入 | 下载模板并上传 Excel（原型 Toast） |',
  '| 导出 | 导出当前筛选结果 |',
  '| 保存 | 勾选记录后设为未归档，保存后不可编辑 |',
  '| 设置为归档 | 勾选记录后锁定为已归档 |',
  '',
  '表格底部提供分页，可切换页码与每页条数。',
  '',
  '---',
].join('\n');
markdownMap['lbl-col-archive-status'] = [
  '## 账单状态',
  '',
  '状态分为**已归档**、**未归档**、**草稿**。',
  '',
  '**仅草稿**状态的数据可以编辑；未归档、已归档均不可编辑。',
  '工具栏「保存」：勾选记录后设为**未归档**。',
  '工具栏「设置为归档」：勾选记录后设为**已归档**。',
  '',
  '---',
].join('\n');
markdownMap['lbl-btn-save-unarchived'] = [
  '## 保存',
  '',
  '勾选台账记录后点击，将账单状态设为**未归档**。未归档数据不可编辑，仅草稿可编辑。',
  '',
  '---',
].join('\n');
markdownMap['lbl-btn-set-archived'] = [
  '## 设置为归档',
  '',
  '勾选台账记录后点击，将账单状态设为**已归档**并锁定编辑。',
  '',
  '---',
].join('\n');

function parseColumnTitles(source) {
  const titles = {};
  for (const match of source.matchAll(/\{[^{}]*annotationId:\s*'(lbl-[^']+)'[^{}]*\}/gs)) {
    const block = match[0];
    const id = match[1];
    const title = block.match(/title:\s*'([^']+)'/)?.[1];
    if (title) titles[id] = title;
  }
  return titles;
}

const columnsSource = fs.readFileSync(columnsPath, 'utf8');
const columnAnnotationIds = [...columnsSource.matchAll(/annotationId:\s*'(lbl-[^']+)'/g)].map((m) => m[1]);
const columnTitles = parseColumnTitles(columnsSource);

const tipsSource = fs.readFileSync(tipsPath, 'utf8');
const columnHeaderTips = Object.fromEntries(
  [...tipsSource.matchAll(/'(lbl-col-[^']+)':\s*\n?\s*'([^']*(?:\\'[^']*)*)'/gs)].map((m) => [
    m[1],
    m[2].replace(/\\'/g, "'"),
  ]),
);


function buildColumnFieldMarkdown(id) {
  const spec = FIELD_ANNOTATION_SPEC[id];
  const title = columnTitles[id] ?? titleFromMarkdown(markdownMap[id]) ?? id.replace(/^lbl-col-/, '');
  const tip = columnHeaderTips[id];
  const lines = [`## ${title}`, ''];
  if (spec?.source) lines.push(`**数据来源**：${spec.source}`);
  if (spec?.formula) lines.push(`**计算方式**：${spec.formula}`);
  if (spec?.editable) lines.push(`**录入方式**：${spec.editable}`);
  if (tip) lines.push('', `**业务说明**：${tip}`);
  lines.push('', '---');
  return lines.join('\n');
}

const NODE_META = {
  'lbl-filter': { title: '筛选条件', color: '#2563eb', aiPrompt: '年份、月份、部门、业务员等筛选。' },
  'lbl-kpi': { title: 'KPI 统计', color: '#64748b', aiPrompt: '六张统计卡片口径。' },
  'lbl-kpi-count': { title: '台账条数', color: '#64748b', aiPrompt: '台账条数 KPI 点击切换列表。' },
  'lbl-kpi-unreceived': { title: '未收总计', color: '#64748b', aiPrompt: '未收总计 KPI 筛选未收款。' },
  'lbl-toolbar': { title: '列表工具栏', color: '#0f766e', aiPrompt: '导入、导出、保存、设置为归档。' },
  'lbl-btn-save-unarchived': { title: '保存', color: '#0f766e', aiPrompt: '勾选记录批量设为未归档。' },
  'lbl-btn-set-archived': { title: '设置为归档', color: '#0f766e', aiPrompt: '勾选记录批量归档。' },
  'lbl-table': { title: '租赁台账宽表', color: '#2563eb', aiPrompt: '运营明细台账列表与行操作。' },
};

function extractSection(md, heading) {
  const lines = md.split('\n');
  const start = lines.findIndex((line) => line.startsWith(heading));
  if (start < 0) return null;
  const level = heading.match(/^#+/)?.[0].length ?? 2;
  let end = lines.length;
  for (let i = start + 1; i < lines.length; i++) {
    if (/^#{1,6}\s/.test(lines[i])) {
      const l = lines[i].match(/^#+/)?.[0].length ?? 2;
      if (l <= level) {
        end = i;
        break;
      }
    }
  }
  return lines.slice(start, end).join('\n').trim();
}

function titleFromMarkdown(md) {
  const match = md.match(/^##\s+(.+)/m);
  if (!match) return null;
  return match[1].replace(/列$/u, '').trim();
}

function resolveMeta(id) {
  if (NODE_META[id]) return NODE_META[id];
  const md = markdownMap[id];
  const fromMd = md ? titleFromMarkdown(md) : null;
  const fromColumn = columnTitles[id];
  if (fromColumn) {
    return { title: fromColumn, color: '#64748b', aiPrompt: `${fromColumn}字段的数据来源与计算口径。` };
  }
  if (fromMd) {
    return { title: fromMd, color: '#64748b', aiPrompt: `${fromMd}字段说明。` };
  }
  return { title: id, color: '#64748b', aiPrompt: id };
}

function trimDoc(md) {
  return (md ?? '').replace(/\n---\s*$/g, '').trim();
}

/** 将标注文档中的 ## 降为 ###，用于 PRD 子节 */
function asSubsection(md) {
  return trimDoc(md).replace(/^## /gm, '### ');
}

function prdSection(title, body) {
  const content = trimDoc(body);
  return content ? `## ${title}\n\n${content}` : `## ${title}`;
}

function buildFullPrd(map, columnIds) {
  const fieldSections = columnIds
    .filter((id) => id !== 'lbl-col-status')
    .map((id) => asSubsection(map[id]))
    .filter(Boolean);

  return [
    '# 租赁业务台账 · 产品需求说明（PRD）',
    '',
    '> 对齐《租赁业务运营明细台账模版》；业务服务组维护各自台账，收款关联与状态自动计算为原型演示。',
    '',
    '---',
    '',
    prdSection(
      '1. 模块定位',
      [
        '| 项 | 说明 |',
        '|---|---|',
        '| 模块名称 | 台账数据 — 租赁业务台账 |',
        '| 目标用户 | 租赁业务客服、业务服务组主管 |',
        '| 核心任务 | 维护租赁运营明细、汇总应收实收与盈亏、关联收款记录 |',
        '| 页面结构 | 筛选区 + KPI 统计 + 工具栏 + 宽表 + 底部分页 |',
      ].join('\n'),
    ),
    '',
    '---',
    '',
    trimDoc(map['lbl-filter']),
    '',
    '---',
    '',
    trimDoc(map['lbl-kpi']),
    '',
    asSubsection(map['lbl-kpi-count']),
    '',
    asSubsection(map['lbl-kpi-unreceived']),
    '',
    '---',
    '',
    trimDoc(map['lbl-toolbar']),
    '',
    asSubsection(map['lbl-btn-save-unarchived']),
    '',
    asSubsection(map['lbl-btn-set-archived']),
    '',
    '---',
    '',
    trimDoc(map['lbl-table']),
    '',
    '---',
    '',
    (() => {
      const body = trimDoc(map['lbl-col-status']).replace(/^##\s+(状态流转|收款状态)\s*\n+/, '');
      return prdSection('6. 收款状态', body);
    })(),
    '',
    '---',
    '',
    prdSection('7. 字段说明', fieldSections.join('\n\n')),
  ]
    .filter((block) => block.trim())
    .join('\n\n');
}

function ensureMarkdown(id, meta) {
  if (id.startsWith('lbl-col-')) {
    return buildColumnFieldMarkdown(id);
  }
  if (markdownMap[id]?.trim()) return markdownMap[id];
  const prdFallback = {
    'lbl-filter': '## 2. 筛选区',
    'lbl-kpi': '## 3. KPI 统计卡片（6 张）',
    'lbl-toolbar': '## 4. 列表工具栏',
    'lbl-table': '## 5. 列表字段',
  };
  if (prdFallback[id] && legacyPrd) {
    return extractSection(legacyPrd, prdFallback[id]) ?? `# ${meta.title}\n\n${meta.aiPrompt}`;
  }
  return `# ${meta.title}\n\n${meta.aiPrompt}`;
}

const pageNodeIds = [
  'lbl-filter',
  'lbl-kpi',
  'lbl-kpi-count',
  'lbl-kpi-unreceived',
  'lbl-toolbar',
  'lbl-btn-save-unarchived',
  'lbl-btn-set-archived',
  'lbl-table',
];

const uniqueOrdered = [...pageNodeIds];
for (const id of columnAnnotationIds) {
  if (!uniqueOrdered.includes(id)) uniqueOrdered.push(id);
}
for (const id of Object.keys(markdownMap)) {
  if (!uniqueOrdered.includes(id)) uniqueOrdered.push(id);
}

const existingNodeById = Object.fromEntries((existing?.data?.nodes ?? []).map((n) => [n.id, n]));
const now = Date.now();

const nodes = uniqueOrdered.map((id, index) => {
  const meta = resolveMeta(id);
  const markdown = ensureMarkdown(id, meta);
  markdownMap[id] = markdown;
  const prev = existingNodeById[id];
  return {
    id,
    index: index + 1,
    title: meta.title,
    pageId: 'list',
    locator: {
      selectors: [`[data-annotation-id="${id}"]`],
      fingerprint: id,
      path: [],
    },
    aiPrompt: meta.aiPrompt,
    annotationText: markdown,
    hasMarkdown: true,
    color: meta.color,
    images: prev?.images ?? [],
    createdAt: prev?.createdAt ?? 1740787200000,
    updatedAt: prev?.updatedAt ?? now,
    controls: prev?.controls ?? [],
  };
});

function docMarkdown(nodeId) {
  return markdownMap[nodeId] ?? '';
}

function docNode(nodeId) {
  const meta = resolveMeta(nodeId);
  return {
    type: 'markdown',
    id: `lbl-doc-${nodeId}`,
    title: meta.title,
    markdown: docMarkdown(nodeId),
  };
}

const tableColumnDocIds = columnAnnotationIds;

const fullPrd = buildFullPrd(markdownMap, columnAnnotationIds);
fs.writeFileSync(prdPath, `${fullPrd.trim()}\n`, 'utf8');

const overviewMd = extractSection(fullPrd, '## 1. 模块定位') ?? fullPrd;

const source = {
  documentVersion: 1,
  format: 'axhub-annotation-source',
  data: {
    version: 2,
    prototypeName: 'lease-business-ledger',
    pageId: 'list',
    updatedAt: now,
    nodes,
  },
  markdownMap,
  assetMap: existing?.assetMap ?? {},
  directory: {
    nodes: [
      {
        type: 'folder',
        id: 'lbl-doc-root',
        title: '租赁业务台账说明',
        defaultExpanded: true,
        children: [
          {
            type: 'markdown',
            id: 'lbl-doc-overview',
            title: '模块总览',
            markdown: overviewMd,
          },
          {
            type: 'link',
            id: 'lbl-link-self',
            title: '租赁业务台账原型',
            href: '/prototypes/lease-business-ledger',
            target: 'self',
          },
          {
            type: 'markdown',
            id: 'lbl-doc-prd',
            title: 'PRD 全文',
            markdown: fullPrd,
            markdownPath: 'src/prototypes/lease-business-ledger/.spec/requirements-prd.md',
          },
          {
            type: 'folder',
            id: 'lbl-doc-page-annotations',
            title: '页面标注',
            defaultExpanded: true,
            children: [
              docNode('lbl-filter'),
              {
                type: 'folder',
                id: 'lbl-doc-folder-kpi',
                title: 'KPI 统计',
                defaultExpanded: false,
                children: [
                  docNode('lbl-kpi'),
                  docNode('lbl-kpi-count'),
                  docNode('lbl-kpi-unreceived'),
                ],
              },
              {
                type: 'folder',
                id: 'lbl-doc-folder-toolbar',
                title: '列表工具栏',
                defaultExpanded: false,
                children: [
                  docNode('lbl-toolbar'),
                  docNode('lbl-btn-save-unarchived'),
                  docNode('lbl-btn-set-archived'),
                ],
              },
              {
                type: 'folder',
                id: 'lbl-doc-folder-table',
                title: '租赁台账宽表',
                defaultExpanded: true,
                children: [
                  docNode('lbl-table'),
                  ...tableColumnDocIds.map((id) => docNode(id)),
                ],
              },
            ],
          },
        ],
      },
    ],
  },
};

fs.writeFileSync(sourcePath, `${JSON.stringify(source, null, 2)}\n`, 'utf8');
console.log(`Built requirements-prd.md and annotation-source.json with ${nodes.length} nodes.`);
