/**
 * PR-37 Domain Intelligence & Delivery Planning — Test Suite
 *
 * Part M：全覆盖测试
 *
 * 覆盖：
 *   A — Domain Registry
 *   B — Domain Classification
 *   C — Industry Epic Generation
 *   D — Industry Feature Generation
 *   E — Domain Validation
 *   F — Sprint Planning
 *   G — Release Planning
 *   H — Batch Planning
 *   I — Capacity Planning
 *   J — Roadmap Alignment
 *   K — Factory Integration
 *   Z — Regression (SF-01, SF-02, PR-35, PR-36)
 */

import { describe, it } from "node:test";
import assert from "node:assert/strict";

// ─── Domain Registry (Part A) ──────────────────────
import {
  getDomainRegistry, getDomain, listDomains,
  getDomainsByCategory, searchDomains, DOMAINS, DOMAIN_CATEGORY,
} from "../src/pr-37-domain-intelligence/domain-registry.mjs";

// ─── Domain Intelligence (Parts B, C, D, E) ────────
import {
  classifyProduct,
} from "../src/pr-37-domain-intelligence/domain-classifier.mjs";

import {
  generateIndustryEpics, resetEpicCounter, describeDomain, listDomainEpics,
} from "../src/pr-37-domain-intelligence/industry-epic-generator.mjs";

import {
  generateIndustryFeatures, resetFeatureCounter, detectFeatureType,
} from "../src/pr-37-domain-intelligence/industry-feature-generator.mjs";

import {
  validateEpics, validateFeatures,
} from "../src/pr-37-domain-intelligence/domain-validator.mjs";

import { createDomainIntelligenceFactory } from "../src/pr-37-domain-intelligence/index.mjs";

// ─── Delivery Planning (Parts F, G, H, I, J) ──────
import {
  generateSprintPlan, defaultSprintConfig,
} from "../src/pr-37-delivery-planning/sprint-planner.mjs";

import {
  generateReleasePlan,
} from "../src/pr-37-delivery-planning/release-planner.mjs";

import {
  generateBatchPlan,
} from "../src/pr-37-delivery-planning/batch-planner.mjs";

import {
  generateCapacityPlan, defaultCapacityConfig,
} from "../src/pr-37-delivery-planning/capacity-planner.mjs";

import {
  alignRoadmapWithPlans,
} from "../src/pr-37-delivery-planning/roadmap-aligner.mjs";

import {
  createDeliveryPlanningFactory, PR37_ARTIFACTS,
} from "../src/pr-37-delivery-planning/index.mjs";

// ─── Regression Suite ──────────────────────────────
import { createFactoryRegistry } from "../src/software-factory-core/factory-registry.mjs";
import { createFactoryInput } from "../src/software-factory-core/factory-contract.mjs";
import { registerSF01 } from "../src/sf-01-product-strategy/index.mjs";
import { registerSF02 } from "../src/sf-02-requirement-engineering/index.mjs";

// ═════════════════════════════════════════════════════
// Test Fixtures
// ═════════════════════════════════════════════════════

function mockStories(count = 30) {
  return Array.from({ length: count }, (_, i) => ({
    id: `us-${i + 1}`,
    statement: `As a user, I want feature ${i + 1}, so that I can work better.`,
    role: "用户",
    goal: `feature ${i + 1}`,
    value: "better work",
    priority: i < 10 ? "Must Have" : i < 20 ? "Should Have" : "Could Have",
    storyPoints: i < 10 ? 3 : i < 20 ? 2 : 1,
    featureId: `ft-${Math.floor(i / 5) + 1}`,
    epicId: `ep-${Math.floor(i / 8) + 1}`,
  }));
}

function mockEpics(count = 4) {
  return Array.from({ length: count }, (_, i) => ({
    id: `ep-${i + 1}`,
    title: ["财务管理", "采购管理", "库存管理", "销售管理"][i] || `Epic ${i + 1}`,
    description: `Description for epic ${i + 1}`,
    category: "管理",
    objective: `Objective ${i + 1}`,
  }));
}

function mockFeatures(count = 6) {
  return Array.from({ length: count }, (_, i) => ({
    id: `ft-${i + 1}`,
    title: `Feature ${i + 1}`,
    description: `Description for feature ${i + 1}`,
    epicId: `ep-${Math.floor(i / 2) + 1}`,
    featureType: "CRUD",
  }));
}

function mockMVPScope() {
  return {
    mvp: { label: "MVP", epics: 2, features: 2, userStories: 10, totalStoryPoints: 30 },
    v1: { label: "V1", epics: 4, features: 4, userStories: 20, totalStoryPoints: 50 },
    v2: { label: "V2", epics: 4, features: 6, userStories: 30, totalStoryPoints: 60 },
    enterprise: { label: "Enterprise", epics: 4, features: 6, userStories: 30 },
    global: { label: "Global", epics: 4, features: 6, userStories: 30 },
    phases: [
      { name: "mvp", scope: "最小可行产品", duration: 3, budget: 300000 },
      { name: "v1", scope: "第一完整版本", duration: 4, budget: 500000 },
      { name: "v2", scope: "功能增强版本", duration: 3, budget: 300000 },
    ],
  };
}

function mockPriors(stories) {
  return stories.map(s => ({
    itemId: s.id, itemType: "story", category: s.priority,
    score: s.priority === "Must Have" ? 100 : s.priority === "Should Have" ? 70 : 40,
  }));
}

// ═════════════════════════════════════════════════════
// A — Domain Registry
// ═════════════════════════════════════════════════════

describe("PR-37 Part A — Domain Registry", () => {

  it("registers exactly 16 domains", () => {
    const domains = listDomains();
    assert.equal(domains.length, 16);
  });

  it("each domain has all 10 knowledge dimensions", () => {
    for (const name of listDomains()) {
      const d = getDomain(name);
      assert.ok(d.name);
      assert.ok(d.displayName);
      assert.ok(d.description);
      assert.ok(d.coreProcesses.length >= 3, `${name}: coreProcesses`);
      assert.ok(d.coreEntities.length >= 3, `${name}: coreEntities`);
      assert.ok(d.coreEpics.length >= 5, `${name}: coreEpics`);
      assert.ok(Object.keys(d.coreFeatures).length >= 3, `${name}: coreFeatures`);
      assert.ok(d.coreKPIs.length >= 3, `${name}: coreKPIs`);
      assert.ok(d.coreRoles.length >= 3, `${name}: coreRoles`);
      assert.ok(d.terminology.length >= 2, `${name}: terminology`);
      assert.ok(d.constraints.length >= 1, `${name}: constraints`);
    }
  });

  it("ERP domain has 10 core epics", () => {
    const erp = getDomain("ERP");
    assert.equal(erp.coreEpics.length, 10);
    const titles = erp.coreEpics.map(e => e.title);
    assert.ok(titles.includes("财务管理"));
    assert.ok(titles.includes("采购管理"));
    assert.ok(titles.includes("库存管理"));
    assert.ok(titles.includes("生产管理"));
  });

  it("MES domain has 10 core epics", () => {
    const mes = getDomain("MES");
    assert.equal(mes.coreEpics.length, 10);
    const titles = mes.coreEpics.map(e => e.title);
    assert.ok(titles.includes("生产执行"));
    assert.ok(titles.includes("质量管理"));
    assert.ok(titles.includes("设备管理"));
    assert.ok(titles.includes("工单管理"));
  });

  it("CRM domain has 9 core epics", () => {
    const crm = getDomain("CRM");
    assert.ok(crm.coreEpics.length >= 7);
    const titles = crm.coreEpics.map(e => e.title);
    assert.ok(titles.includes("客户管理"));
    assert.ok(titles.includes("商机管理"));
    assert.ok(titles.includes("销售漏斗"));
  });

  it("AI Platform domain has 8 core epics", () => {
    const ai = getDomain("AI Platform");
    assert.ok(ai.coreEpics.length >= 6);
    const titles = ai.coreEpics.map(e => e.title);
    assert.ok(titles.includes("知识库管理"));
    assert.ok(titles.includes("Agent管理"));
  });

  it("getDomain returns null for unknown domain", () => {
    assert.equal(getDomain("UnknownDomain"), null);
  });

  it("searchDomains finds by keyword", () => {
    const results = searchDomains("MES");
    assert.ok(results.length >= 1);
    assert.equal(results[0].name, "MES");
  });

  it("getDomainsByCategory filters correctly", () => {
    const enterprise = getDomainsByCategory(DOMAIN_CATEGORY.ENTERPRISE_SOFTWARE);
    assert.ok(enterprise.length >= 3);
  });
});

// ═════════════════════════════════════════════════════
// B — Domain Classification
// ═════════════════════════════════════════════════════

describe("PR-37 Part B — Domain Classification", () => {

  it("classifies ERP system correctly", () => {
    const result = classifyProduct({ productName: "ERP系统", description: "企业资源计划" });
    assert.equal(result.primaryDomain, "ERP");
    assert.ok(result.confidenceScore >= 0.3);
    assert.ok(result.matchedKeywords.length >= 1);
  });

  it("classifies MES system correctly", () => {
    const result = classifyProduct({ productName: "工业MES系统", description: "制造执行系统" });
    assert.equal(result.primaryDomain, "MES");
    assert.ok(result.confidenceScore >= 0.5);
  });

  it("classifies AI customer service platform", () => {
    const result = classifyProduct({ productName: "AI客服平台", description: "智能客服系统" });
    assert.equal(result.primaryDomain, "AI Platform");
  });

  it("classifies CRM system", () => {
    const result = classifyProduct({ productName: "CRM系统", description: "客户关系管理" });
    assert.equal(result.primaryDomain, "CRM");
  });

  it("classifies cross-border ecommerce with secondary", () => {
    const result = classifyProduct({ productName: "跨境电商平台", description: "跨境电商" });
    assert.equal(result.primaryDomain, "E-Commerce");
    assert.ok(result.secondaryDomain);
  });

  it("classifies industrial AI quality inspection", () => {
    const result = classifyProduct({ productName: "工业AI质检", description: "智能制造AI质检" });
    assert.equal(result.primaryDomain, "MES");
  });

  it("classifies WMS warehouse", () => {
    const result = classifyProduct({ productName: "WMS仓库", description: "仓储管理" });
    assert.equal(result.primaryDomain, "WMS");
  });

  it("returns null for empty input", () => {
    const result = classifyProduct({ productName: "", description: "" });
    assert.equal(result.primaryDomain, null);
    assert.equal(result.confidenceScore, 0);
    assert.ok(result.classificationReason);
  });

  it("returns null for null input", () => {
    const result = classifyProduct(null);
    assert.equal(result.primaryDomain, null);
    assert.equal(result.confidenceScore, 0);
  });
});

// ═════════════════════════════════════════════════════
// C — Industry Epic Generation
// ═════════════════════════════════════════════════════

describe("PR-37 Part C — Industry Epic Generation", () => {

  it("generates ERP-specific epics with domain vocabulary", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("ERP", { productName: "ERP系统" });
    assert.equal(epics.length, 10);
    const titles = epics.map(e => e.title);
    assert.ok(titles.includes("财务管理"));
    assert.ok(titles.includes("采购管理"));
    assert.ok(titles.includes("生产管理"));
    // Should NOT have generic "内容管理"
    assert.ok(!titles.includes("内容管理"));
  });

  it("generates MES-specific epics", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("MES", { productName: "工业MES系统" });
    assert.equal(epics.length, 10);
    const titles = epics.map(e => e.title);
    assert.ok(titles.includes("质量管理"));
    assert.ok(titles.includes("设备管理"));
    assert.ok(titles.includes("追溯管理"));
  });

  it("generates AI Platform epics", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("AI Platform", { productName: "AI客服平台" });
    assert.ok(epics.length >= 6);
    const titles = epics.map(e => e.title);
    assert.ok(titles.includes("知识库管理"));
    assert.ok(titles.includes("Agent管理"));
  });

  it("each epic has all required fields", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("ERP", { productName: "ERP系统" });
    for (const epic of epics) {
      assert.ok(epic.id.startsWith("ep-"));
      assert.ok(epic.title);
      assert.ok(epic.description);
      assert.ok(epic.category);
      assert.ok(epic.objective);
      assert.ok(epic.successMetric);
    }
  });

  it("falls back to generic template for unknown domain", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("量子计算", { productName: "量子计算机" });
    assert.ok(epics.length >= 5);
    // Generic epics shouldn't have ERP-specific ones
    const titles = epics.map(e => e.title);
    assert.ok(!titles.includes("财务管理"));
  });
});

// ═════════════════════════════════════════════════════
// D — Industry Feature Generation
// ═════════════════════════════════════════════════════

describe("PR-37 Part D — Industry Feature Generation", () => {

  it("generates ERP features from domain registry", () => {
    resetEpicCounter(); resetFeatureCounter();
    const epics = generateIndustryEpics("ERP", { productName: "ERP系统" });
    const features = generateIndustryFeatures("ERP", epics);
    assert.ok(features.length >= 50);
    const titles = features.map(f => f.title);
    assert.ok(titles.includes("总账管理"));
    assert.ok(titles.includes("供应商管理"));
  });

  it("detects feature types correctly", () => {
    assert.equal(detectFeatureType("数据分析"), "analytics");
    assert.equal(detectFeatureType("审批流程"), "workflow");
    assert.equal(detectFeatureType("统计分析"), "analytics");
    assert.equal(detectFeatureType("消息推送"), "notification");
    assert.equal(detectFeatureType("搜索"), "search");
    assert.equal(detectFeatureType("系统设置"), "configuration");
    assert.equal(detectFeatureType("用户管理"), "CRUD");
  });

  it("each feature references correct epicId", () => {
    resetEpicCounter(); resetFeatureCounter();
    const epics = generateIndustryEpics("ERP", { productName: "ERP系统" });
    const features = generateIndustryFeatures("ERP", epics);
    const epicIds = new Set(epics.map(e => e.id));
    for (const f of features) {
      assert.ok(epicIds.has(f.epicId), `Feature ${f.title} epicId ${f.epicId} not in epics`);
    }
  });

  it("each feature has id with ft- prefix", () => {
    resetEpicCounter(); resetFeatureCounter();
    const epics = generateIndustryEpics("MES", { productName: "MES系统" });
    const features = generateIndustryFeatures("MES", epics);
    for (const f of features) {
      assert.ok(f.id.startsWith("ft-"));
    }
  });
});

// ═════════════════════════════════════════════════════
// E — Domain Validation
// ═════════════════════════════════════════════════════

describe("PR-37 Part E — Domain Validation", () => {

  it("validates ERP epics with 100% coverage", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("ERP", { productName: "ERP系统" });
    const result = validateEpics(epics, "ERP");
    assert.equal(result.overallVerdict, "pass");
    assert.equal(result.coverageScore, 100);
    assert.equal(result.completenessScore, 100);
  });

  it("validates MES epics with 100% coverage", () => {
    resetEpicCounter();
    const epics = generateIndustryEpics("MES", { productName: "MES系统" });
    const result = validateEpics(epics, "MES");
    assert.equal(result.overallVerdict, "pass");
    assert.equal(result.coverageScore, 100);
  });

  it("detects generic epics as low coverage for ERP", () => {
    const genericEpics = [
      { title: "用户管理" }, { title: "内容管理" }, { title: "业务流程" },
    ];
    const result = validateEpics(genericEpics, "ERP");
    assert.ok(result.coverageScore < 100);
    assert.ok(result.missingEpics.length > 0);
    assert.equal(result.overallVerdict, "fail");
  });

  it("validates features consistency", () => {
    resetEpicCounter(); resetFeatureCounter();
    const epics = generateIndustryEpics("ERP", { productName: "ERP系统" });
    const features = generateIndustryFeatures("ERP", epics);
    const result = validateFeatures(features, "ERP");
    assert.ok(result.consistencyScore >= 70);
  });

  it("handles unknown domain gracefully", () => {
    const result = validateEpics([{ title: "Test" }], "UnknownDomain");
    assert.equal(result.coverageScore, 0);
    assert.equal(result.overallVerdict, "fail");
  });
});

// ═════════════════════════════════════════════════════
// F — Sprint Planning
// ═════════════════════════════════════════════════════

describe("PR-37 Part F — Sprint Planning", () => {

  it("generates sprints from Must Have stories", () => {
    const stories = mockStories(30);
    const priors = mockPriors(stories);
    const result = generateSprintPlan({
      stories, dependencies: [], priorities: priors,
      config: defaultSprintConfig({ teamVelocity: 20 }),
    });
    assert.ok(result.sprints.length >= 1, `Expected >=1 sprints, got ${result.sprints.length}`);
    assert.ok(result.metrics.totalSprints >= 1);
  });

  it("respects sprint capacity", () => {
    const stories = mockStories(30);
    const priors = mockPriors(stories);
    const result = generateSprintPlan({
      stories, dependencies: [], priorities: priors,
      config: defaultSprintConfig({ teamVelocity: 15, maxStoryPointsPerSprint: 15 }),
    });
    for (const sprint of result.sprints) {
      assert.ok(sprint.totalStoryPoints <= 15 + 5, // allow small overflow
        `Sprint ${sprint.sprintNumber}: ${sprint.totalStoryPoints} pts > 20`);
    }
  });

  it("each sprint has required fields", () => {
    const result = generateSprintPlan({
      stories: mockStories(20), dependencies: [], priorities: mockPriors(mockStories(20)),
    });
    for (const s of result.sprints) {
      assert.ok(s.sprintNumber);
      assert.ok(s.sprintGoal);
      assert.ok(s.startDate);
      assert.ok(s.endDate);
      assert.ok(Array.isArray(s.storyIds));
      assert.ok(s.totalStoryPoints >= 0);
      assert.ok(Array.isArray(s.risks));
    }
  });

  it("handles single story", () => {
    const stories = [{ id: "us-1", statement: "test", priority: "Must Have", storyPoints: 3, featureId: "ft-1", epicId: "ep-1" }];
    const priors = [{ itemId: "us-1", itemType: "story", category: "Must Have", score: 100 }];
    const result = generateSprintPlan({ stories, dependencies: [], priorities: priors });
    assert.equal(result.sprints.length, 1);
    assert.equal(result.sprints[0].storyIds.length, 1);
  });

  it("handles empty stories", () => {
    const result = generateSprintPlan({ stories: [], dependencies: [], priorities: [] });
    assert.equal(result.sprints.length, 0);
    assert.equal(result.metrics.totalSprints, 0);
  });

  it("respects dependency order", () => {
    const stories = [
      { id: "us-1", statement: "base", priority: "Must Have", storyPoints: 5, featureId: "ft-1", epicId: "ep-1" },
      { id: "us-2", statement: "dependent", priority: "Must Have", storyPoints: 5, featureId: "ft-1", epicId: "ep-1" },
      { id: "us-3", statement: "filler", priority: "Should Have", storyPoints: 3, featureId: "ft-1", epicId: "ep-1" },
    ];
    const priors = [
      { itemId: "us-1", itemType: "story", category: "Must Have", score: 100 },
      { itemId: "us-2", itemType: "story", category: "Must Have", score: 95 },
      { itemId: "us-3", itemType: "story", category: "Should Have", score: 70 },
    ];
    // us-2 depends on us-1 (us-2 → us-1 means us-2 requires us-1 first)
    const deps = { edges: [{ from: "us-2", to: "us-1", critical: true }] };
    const result = generateSprintPlan({ stories, dependencies: deps, priorities: priors, config: defaultSprintConfig({ teamVelocity: 8 }) });
    // Both us-1 and us-2 should be in the sprint plan
    const allIds = result.sprints.flatMap(s => s.storyIds);
    assert.ok(allIds.includes("us-1"), "us-1 should be planned");
    assert.ok(allIds.includes("us-2"), "us-2 should be planned");
    // us-2 must not be assigned before us-1 (dependency constraint)
    const s1 = result.sprints.find(s => s.storyIds.includes("us-1"));
    const s2 = result.sprints.find(s => s.storyIds.includes("us-2"));
    assert.ok(s1.sprintNumber <= s2.sprintNumber,
      `us-1 (Sprint ${s1.sprintNumber}) must not be after us-2 (Sprint ${s2.sprintNumber})`);
  });
});

// ═════════════════════════════════════════════════════
// G — Release Planning
// ═════════════════════════════════════════════════════

describe("PR-37 Part G — Release Planning", () => {

  it("generates 5 releases from mvpScope", () => {
    const result = generateReleasePlan({
      mvpScope: mockMVPScope(),
      priorities: mockPriors(mockStories(30)),
      dependencies: [],
      stories: mockStories(30),
      epics: mockEpics(4),
      features: mockFeatures(6),
    });
    assert.equal(result.releases.length, 5);
    const versions = result.releases.map(r => r.version);
    assert.ok(versions.includes("1.0.0"));
    assert.ok(versions.includes("2.0.0"));
  });

  it("R1.0 (MVP) contains Must Have stories", () => {
    const stories = mockStories(30);
    const result = generateReleasePlan({
      mvpScope: mockMVPScope(),
      priorities: mockPriors(stories),
      dependencies: [],
      stories,
      epics: mockEpics(4),
      features: mockFeatures(6),
    });
    const r1 = result.releases[0];
    assert.ok(r1.features.storyCount > 0);
    assert.ok(r1.validationGates.length >= 3);
  });

  it("each release has validation gates and goals", () => {
    const result = generateReleasePlan({
      mvpScope: mockMVPScope(),
      priorities: mockPriors(mockStories(30)),
      dependencies: [],
      stories: mockStories(30),
      epics: mockEpics(4),
      features: mockFeatures(6),
    });
    for (const release of result.releases) {
      assert.ok(release.version);
      assert.ok(release.name);
      assert.ok(Array.isArray(release.validationGates));
      assert.ok(release.releaseGoals);
    }
  });

  it("handles null mvpScope gracefully", () => {
    const result = generateReleasePlan({
      mvpScope: null,
      priorities: [],
      dependencies: [],
      stories: [],
      epics: [],
      features: [],
    });
    assert.ok(result.releases);
  });
});

// ═════════════════════════════════════════════════════
// H — Batch Planning
// ═════════════════════════════════════════════════════

describe("PR-37 Part H — Batch Planning", () => {

  it("generates batches with dependency levels", () => {
    const stories = [
      { id: "us-1", statement: "no deps", priority: "Must Have", storyPoints: 3, featureId: "ft-1", epicId: "ep-1" },
      { id: "us-2", statement: "dep on 1", priority: "Must Have", storyPoints: 2, featureId: "ft-1", epicId: "ep-1" },
      { id: "us-3", statement: "dep on 2", priority: "Should Have", storyPoints: 1, featureId: "ft-1", epicId: "ep-1" },
    ];
    const deps = {
      edges: [
        { from: "us-2", to: "us-1", critical: true },
        { from: "us-3", to: "us-2", critical: true },
      ],
    };
    const result = generateBatchPlan({
      stories,
      dependencies: deps,
      priorities: mockPriors(stories),
      sprints: { sprints: [] },
      releases: { releases: [] },
    });
    assert.ok(result.batches.length >= 1);
    // Should have at least a DevelopmentBatch with dependency levels
    const devBatch = result.batches.find(b => b.batchType === "DevelopmentBatch");
    assert.ok(devBatch);
  });

  it("generates all 4 batch types when data is sufficient", () => {
    const stories = mockStories(20);
    const sp = generateSprintPlan({ stories, dependencies: [], priorities: mockPriors(stories) });
    const rp = generateReleasePlan({
      mvpScope: mockMVPScope(), priorities: mockPriors(stories),
      dependencies: [], stories, epics: mockEpics(4), features: mockFeatures(6),
    });
    const result = generateBatchPlan({
      stories, dependencies: [], priorities: mockPriors(stories),
      sprints: sp, releases: rp.releases,
    });
    assert.ok(result.batches.length >= 1);
    const types = new Set(result.batches.map(b => b.batchType));
    assert.ok(types.has("DevelopmentBatch"));
  });
});

// ═════════════════════════════════════════════════════
// I — Capacity Planning
// ═════════════════════════════════════════════════════

describe("PR-37 Part I — Capacity Planning", () => {

  it("calculates capacity from sprint plan", () => {
    const stories = mockStories(20);
    const sp = generateSprintPlan({ stories, dependencies: [], priorities: mockPriors(stories) });
    const cp = generateCapacityPlan({ sprints: sp.sprints, releases: [] });
    assert.ok(cp.totalEffort > 0);
    assert.ok(cp.totalCapacity > 0);
    assert.ok(cp.capacityUtilization.includes("%"));
  });

  it("delivery forecast provides realistic date", () => {
    const stories = mockStories(20);
    const sp = generateSprintPlan({ stories, dependencies: [], priorities: mockPriors(stories) });
    const cp = generateCapacityPlan({ sprints: sp.sprints, releases: [] });
    assert.ok(cp.deliveryForecast.realistic);
    assert.notEqual(cp.deliveryForecast.realistic, "N/A");
  });

  it("handles empty sprint list gracefully", () => {
    const cp = generateCapacityPlan({ sprints: [], releases: [] });
    assert.equal(cp.totalEffort, 0);
  });
});

// ═════════════════════════════════════════════════════
// J — Roadmap Alignment
// ═════════════════════════════════════════════════════

describe("PR-37 Part J — Roadmap Alignment", () => {

  it("aligns roadmap with sprint and release plans", () => {
    const stories = mockStories(30);
    const sp = generateSprintPlan({ stories, dependencies: [], priorities: mockPriors(stories) });
    const rp = generateReleasePlan({
      mvpScope: mockMVPScope(), priorities: mockPriors(stories),
      dependencies: [], stories, epics: mockEpics(4), features: mockFeatures(6),
    });
    const bp = generateBatchPlan({ stories, dependencies: [], priorities: mockPriors(stories), sprints: sp.sprints, releases: rp.releases });

    const result = alignRoadmapWithPlans({
      roadmap: mockMVPScope(),
      sprintPlan: sp,
      releasePlan: rp,
      batchPlan: bp,
      mvpScope: mockMVPScope(),
    });
    assert.ok(["aligned", "partial", "misaligned"].includes(result.overallVerdict));
    assert.ok(result.alignmentScore >= 0 && result.alignmentScore <= 100);
    assert.ok(result.summary);
  });
});

// ═════════════════════════════════════════════════════
// K — Factory Integration
// ═════════════════════════════════════════════════════

describe("PR-37 Part K — Factory Integration", () => {

  it("createDomainIntelligenceFactory produces epics + features + validation", () => {
    const result = createDomainIntelligenceFactory({ productName: "ERP系统" });
    assert.equal(result.classification.primaryDomain, "ERP");
    assert.ok(result.epics.length >= 8);
    assert.ok(result.features.length >= 50);
    assert.ok(result.validation);
    assert.equal(result.validation.overallVerdict, "pass");
  });

  it("createDomainIntelligenceFactory accepts domainOverride", () => {
    const result = createDomainIntelligenceFactory(
      { productName: "神秘系统" },
      { domainOverride: "MES" }
    );
    assert.equal(result.classification.primaryDomain, "MES");
    assert.equal(result.classification.confidenceScore, 1.0);
  });

  it("createDeliveryPlanningFactory produces 4 plans", () => {
    const stories = mockStories(30);
    const sf02Data = {
      userStories: stories,
      epics: mockEpics(4),
      features: mockFeatures(6),
      dependencies: { nodes: [], edges: [] },
      priorities: mockPriors(stories),
      mvpScope: mockMVPScope(),
      roadmap: mockMVPScope().phases,
    };
    const result = createDeliveryPlanningFactory(sf02Data);
    assert.equal(result.status, "passed");
    assert.ok(result.sprintPlan.sprints.length >= 1);
    assert.ok(result.releasePlan.releases.length >= 1);
    assert.ok(result.batchPlan.batches.length >= 1);
    assert.ok(result.capacityPlan.totalEffort > 0);
    assert.ok(result.alignmentReport);
    assert.ok(["aligned", "partial", "misaligned"].includes(result.alignmentReport.overallVerdict));
  });

  it("createDeliveryPlanningFactory fails gracefully with no data", () => {
    const result = createDeliveryPlanningFactory(null);
    assert.equal(result.status, "failed");
    assert.ok(result.error);
  });

  it("PR37_ARTIFACTS has all artifact types", () => {
    const types = Object.values(PR37_ARTIFACTS);
    assert.ok(types.includes("sprint-plan"));
    assert.ok(types.includes("release-plan"));
    assert.ok(types.includes("batch-plan"));
    assert.ok(types.includes("capacity-plan"));
    assert.ok(types.includes("alignment-report"));
  });
});

// ═════════════════════════════════════════════════════
// Z — Regression: SF-01, SF-02, PR-35, PR-36
// ═════════════════════════════════════════════════════

describe("PR-37 Part Z — Regression", () => {

  it("SF-01 factory still works after PR-37", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    const input = createFactoryInput({ factoryId: "SF-01", parameters: { idea: "AI客服平台" } });
    const output = registry.execute("SF-01", input);
    assert.equal(output.status, "passed");
  });

  it("SF-02 factory still works after PR-37", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);
    const sf01Out = registry.execute("SF-01", createFactoryInput({ factoryId: "SF-01", parameters: { idea: "AI客服平台" } }));
    const sf02Out = registry.execute("SF-02", createFactoryInput({ factoryId: "SF-02", upstreamArtifacts: sf01Out.artifacts }));
    assert.equal(sf02Out.status, "passed");
    assert.ok(sf02Out.artifacts.length >= 10);
  });

  it("SF-01 → SF-02 → PR-37 full pipeline", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);

    const sf01Out = registry.execute("SF-01", createFactoryInput({ factoryId: "SF-01", parameters: { idea: "ERP系统" } }));
    const sf02Out = registry.execute("SF-02", createFactoryInput({ factoryId: "SF-02", upstreamArtifacts: sf01Out.artifacts }));

    // Extract SF-02 data
    const stories = JSON.parse(sf02Out.artifacts.find(a => a.metadata?.artifactType === "user-story-catalog").content);
    const epics = JSON.parse(sf02Out.artifacts.find(a => a.metadata?.artifactType === "epic-catalog").content);
    const features = JSON.parse(sf02Out.artifacts.find(a => a.metadata?.artifactType === "feature-catalog").content);
    const depGraph = JSON.parse(sf02Out.artifacts.find(a => a.metadata?.artifactType === "dependency-graph").content);
    const priMatrix = JSON.parse(sf02Out.artifacts.find(a => a.metadata?.artifactType === "priority-matrix").content);
    const mvpScope = JSON.parse(sf02Out.artifacts.find(a => a.metadata?.artifactType === "mvp-scope").content);

    // Build pri entries from priMatrix
    const priEntries = [];
    const catMap = { mustHave: "Must Have", shouldHave: "Should Have", couldHave: "Could Have", wontHave: "Won't Have" };
    if (priMatrix?.story) {
      for (const [cat, ids] of Object.entries(priMatrix.story)) {
        if (cat === "summary") continue;
        for (const id of ids) priEntries.push({ itemId: id, itemType: "story", category: catMap[cat] || cat, score: cat === "mustHave" ? 100 : cat === "shouldHave" ? 70 : 40 });
      }
    }

    // PR-37 Domain Intelligence
    const diResult = createDomainIntelligenceFactory({ productName: "ERP系统" });
    assert.equal(diResult.classification.primaryDomain, "ERP");
    assert.ok(diResult.epics.length >= 8);
    assert.equal(diResult.validation.overallVerdict, "pass");

    // PR-37 Delivery Planning
    const dpResult = createDeliveryPlanningFactory({
      userStories: stories, epics, features,
      dependencies: depGraph,
      priorities: priEntries,
      mvpScope,
      roadmap: mvpScope.phases,
    });
    assert.equal(dpResult.status, "passed");
    assert.ok(dpResult.sprintPlan.sprints.length >= 1);
    assert.ok(dpResult.releasePlan.releases.length >= 1);
    assert.ok(dpResult.alignmentReport);
  });

  it("PR-35/PR-36 factory registry topological order preserved", () => {
    const registry = createFactoryRegistry();
    registerSF01(registry);
    registerSF02(registry);
    const order = registry.getTopologicalOrder();
    const sf01Idx = order.indexOf("SF-01");
    const sf02Idx = order.indexOf("SF-02");
    assert.ok(sf01Idx < sf02Idx, "SF-01 must come before SF-02 in topological order");
  });
});
