/**
 * SF-02 — Dependency Engine
 *
 * Part L：建立需求依赖关系。
 *
 * 支持：
 *   - Epic Dependency
 *   - Feature Dependency
 *   - Story Dependency
 *
 * 输出：Dependency Graph
 *
 * @module sf-02-requirement-engineering/dependency-engine
 * @since SF-02
 */

import { createDependency, DEPENDENCY_TYPE } from "./domain-model.mjs";

/**
 * 从需求体系构建完整依赖图。
 *
 * @param {object} opts
 * @param {object[]} opts.epics
 * @param {object[]} opts.features
 * @param {object[]} opts.userStories
 * @returns {{ dependencies: object[], graph: object }}
 */
export function buildDependencyGraph({ epics = [], features = [], userStories = [] }) {
  const dependencies = [];

  // ── 1. Epic Level Dependencies ──

  const epicMap = {};
  for (const e of epics) epicMap[e.title] = e;

  // 系统性依赖：用户管理 → 权限管理
  if (epicMap["用户管理"] && epicMap["权限管理"]) {
    dependencies.push(createDependency({
      fromId: epicMap["权限管理"].id, fromType: "epic",
      toId: epicMap["用户管理"].id, toType: "epic",
      depType: DEPENDENCY_TYPE.REQUIRED_BY,
      description: "权限管理依赖用户管理中定义的用户和角色",
    }));
  }
  if (epicMap["用户与组织管理"] && epicMap["权限与安全"]) {
    dependencies.push(createDependency({
      fromId: epicMap["权限与安全"].id, fromType: "epic",
      toId: epicMap["用户与组织管理"].id, toType: "epic",
      depType: DEPENDENCY_TYPE.REQUIRED_BY,
      description: "权限管理依赖组织架构和用户数据",
    }));
  }

  // 系统性依赖：知识库 → Agent → 对话
  if (epicMap["知识库管理"] && epicMap["Agent管理"]) {
    dependencies.push(createDependency({
      fromId: epicMap["Agent管理"].id, fromType: "epic",
      toId: epicMap["知识库管理"].id, toType: "epic",
      depType: DEPENDENCY_TYPE.REQUIRED_BY,
      description: "Agent 需要知识库提供检索内容",
    }));
  }
  if (epicMap["Agent管理"] && epicMap["对话管理"]) {
    dependencies.push(createDependency({
      fromId: epicMap["对话管理"].id, fromType: "epic",
      toId: epicMap["Agent管理"].id, toType: "epic",
      depType: DEPENDENCY_TYPE.REQUIRED_BY,
      description: "对话管理依赖 Agent 提供智能回复",
    }));
  }

  // 系统性依赖：核心业务 → 运营分析
  if (epicMap["核心业务管理"] && (epicMap["数据分析与报表"] || epicMap["运营分析"])) {
    const analyticsEpic = epicMap["数据分析与报表"] || epicMap["运营分析"];
    dependencies.push(createDependency({
      fromId: analyticsEpic.id, fromType: "epic",
      toId: epicMap["核心业务管理"].id, toType: "epic",
      depType: DEPENDENCY_TYPE.REQUIRED_BY,
      description: "分析引擎依赖核心业务数据",
    }));
  }

  // 系统性依赖：所有 Epic → 运营分析
  const analyticsId = epicMap["运营分析"]?.id || epicMap["数据分析"]?.id || epicMap["数据分析与报表"]?.id;
  if (analyticsId) {
    for (const e of epics) {
      if (e.id === analyticsId) continue;
      if (e.title.includes("系统设置") || e.title.includes("集成")) continue;
      dependencies.push(createDependency({
        fromId: analyticsId, fromType: "epic",
        toId: e.id, toType: "epic",
        depType: DEPENDENCY_TYPE.RELATED_TO,
        description: `运营分析需要 ${e.title} 的数据`,
        critical: false,
      }));
    }
  }

  // ── 2. Feature Level Dependencies ──

  const featureMap = {};
  for (const f of features) featureMap[f.title] = f;

  // 通用：CRUD → 搜索依赖
  for (const f of features) {
    const searchFeature = features.find(x => x.epicId === f.epicId && x.featureType === "search");
    if (searchFeature && f.featureType === "CRUD") {
      dependencies.push(createDependency({
        fromId: searchFeature.id, fromType: "feature",
        toId: f.id, toType: "feature",
        depType: DEPENDENCY_TYPE.RELATED_TO,
        description: `搜索功能依赖 ${f.title} 提供数据源`,
        critical: false,
      }));
    }
  }

  // ── 3. Story Level Dependencies ──

  // CRUD Stories: read → create → update → delete
  const storiesByFeature = {};
  for (const s of userStories) {
    if (!storiesByFeature[s.featureId]) storiesByFeature[s.featureId] = [];
    storiesByFeature[s.featureId].push(s);
  }

  for (const [fid, stories] of Object.entries(storiesByFeature)) {
    const readStory = stories.find(s => s.goal?.includes("浏览") || s.goal?.includes("查看") || s.goal?.includes("列表"));
    const createStory = stories.find(s => s.goal?.includes("创建") || s.goal?.includes("新增") || s.goal?.includes("添加"));
    const editStory = stories.find(s => s.goal?.includes("编辑") || s.goal?.includes("修改"));
    const deleteStory = stories.find(s => s.goal?.includes("删除"));

    if (readStory && createStory) {
      dependencies.push(createDependency({
        fromId: readStory.id, fromType: "story",
        toId: createStory.id, toType: "story",
        depType: DEPENDENCY_TYPE.REQUIRED_BY,
        description: "浏览列表需要在创建数据之后",
      }));
    }
    if (editStory && createStory) {
      dependencies.push(createDependency({
        fromId: editStory.id, fromType: "story",
        toId: createStory.id, toType: "story",
        depType: DEPENDENCY_TYPE.BLOCKS,
        description: "编辑数据需要先有创建的数据",
      }));
    }
    if (deleteStory && createStory) {
      dependencies.push(createDependency({
        fromId: deleteStory.id, fromType: "story",
        toId: createStory.id, toType: "story",
        depType: DEPENDENCY_TYPE.BLOCKS,
        description: "删除数据以存在的创建数据为前提",
      }));
    }
  }

  // ── Build Graph Representation ──

  const graph = {
    nodes: [
      ...epics.map(e => ({ id: e.id, label: e.title, type: "epic" })),
      ...features.map(f => ({ id: f.id, label: f.title, type: "feature" })),
      ...userStories.map(s => ({ id: s.id, label: s.statement, type: "story" })),
    ],
    edges: dependencies.map(d => ({
      from: d.fromId,
      to: d.toId,
      label: d.depType,
      critical: d.critical,
    })),
  };

  return { dependencies, graph };
}

// ═══════════════════════════════════════════════════════
// Prioritization Engine (Part M)
// ═══════════════════════════════════════════════════════

import { createPriority, PRIORITY_CATEGORY, PRIORITY_METHOD } from "./domain-model.mjs";

/**
 * MoSCoW 优先级分类。
 *
 * @param {object[]} items          — 需求项列表 (epic/feature/story)
 * @param {string} itemType         — "epic" | "feature" | "story"
 * @param {object} strategyPackage  — SF-01 策略包
 * @returns {object[]}
 */
export function prioritizeByMoSCoW(items, itemType, strategyPackage) {
  const roadmap = strategyPackage?.roadmap || {};
  const mvpPhase = roadmap?.phases?.find(p => p.phase === "mvp" || p.name?.includes("MVP"));

  return items.map((item, i) => {
    let category;
    let rationale;

    // Priority by index + roadmap alignment
    if (i < Math.ceil(items.length * 0.3)) {
      category = PRIORITY_CATEGORY.MUST_HAVE;
      rationale = "MVP 核心功能，没有它产品无法交付最小可用价值";
    } else if (i < Math.ceil(items.length * 0.6)) {
      category = PRIORITY_CATEGORY.SHOULD_HAVE;
      rationale = "V1 重要功能，显著提升产品竞争力";
    } else if (i < Math.ceil(items.length * 0.85)) {
      category = PRIORITY_CATEGORY.COULD_HAVE;
      rationale = "锦上添花功能，可延后至 V2";
    } else {
      category = PRIORITY_CATEGORY.WONT_HAVE;
      rationale = "当前阶段不实现，列入远期规划";
    }

    // Override: system setup / security epics often Must Have
    if (itemType === "epic") {
      if (item.title === "系统设置" || item.title === "系统管理与配置" || item.title === "权限管理" || item.title === "权限与安全") {
        category = PRIORITY_CATEGORY.MUST_HAVE;
        rationale = "基础架构功能，MVP 必需";
      }
    }

    return createPriority({
      itemId: item.id, itemType,
      category, method: PRIORITY_METHOD.MOSCOW,
      score: category === PRIORITY_CATEGORY.MUST_HAVE ? 100
        : category === PRIORITY_CATEGORY.SHOULD_HAVE ? 70
        : category === PRIORITY_CATEGORY.COULD_HAVE ? 40
        : 10,
      rationale,
    });
  });
}

/**
 * RICE 优先级评分。
 *
 * Reach × Impact × Confidence / Effort
 *
 * @param {object[]} items
 * @param {string} itemType
 * @param {object} strategyPackage
 * @returns {object[]}
 */
export function prioritizeByRICE(items, itemType, strategyPackage) {
  return items.map((item, i) => {
    // Heuristic RICE scoring based on position and item type
    const reach = Math.max(10, 100 - i * 5);           // 早期项 reach 更高
    const impact = itemType === "epic" ? 3 : itemType === "feature" ? 2 : 1;
    const confidence = 0.8;                              // default confidence
    const effort = Math.max(1, Math.ceil(items.length / (i + 1)));

    const score = Math.round((reach * impact * confidence) / effort);

    let category;
    if (score >= 60) category = PRIORITY_CATEGORY.MUST_HAVE;
    else if (score >= 30) category = PRIORITY_CATEGORY.SHOULD_HAVE;
    else if (score >= 10) category = PRIORITY_CATEGORY.COULD_HAVE;
    else category = PRIORITY_CATEGORY.WONT_HAVE;

    return createPriority({
      itemId: item.id, itemType,
      category, method: PRIORITY_METHOD.RICE,
      score,
      scores: { reach, impact, confidence, effort },
      rationale: `RICE = ${reach} × ${impact} × ${confidence} / ${effort} = ${score}`,
    });
  });
}

/**
 * WSJF (Weighted Shortest Job First) 优先级。
 *
 * (Business Value + Time Criticality + Risk Reduction) / Job Duration
 *
 * @param {object[]} items
 * @param {string} itemType
 * @returns {object[]}
 */
export function prioritizeByWSJF(items, itemType) {
  return items.map((item, i) => {
    const bizValue = Math.max(1, 20 - i);
    const timeCriticality = Math.max(1, 15 - i * 0.8);
    const riskReduction = Math.max(1, 10 - i * 0.5);
    const jobDuration = Math.max(1, Math.ceil(items.length / (i + 1)));

    const costOfDelay = bizValue + timeCriticality + riskReduction;
    const score = Math.round((costOfDelay * 100) / jobDuration) / 100;

    let category;
    if (score >= 15) category = PRIORITY_CATEGORY.MUST_HAVE;
    else if (score >= 5) category = PRIORITY_CATEGORY.SHOULD_HAVE;
    else if (score >= 2) category = PRIORITY_CATEGORY.COULD_HAVE;
    else category = PRIORITY_CATEGORY.WONT_HAVE;

    return createPriority({
      itemId: item.id, itemType,
      category, method: PRIORITY_METHOD.WSJF,
      score,
      scores: { bizValue, timeCriticality, riskReduction, jobDuration, costOfDelay },
      rationale: `WSJF = CoD(${costOfDelay}) / Duration(${jobDuration}) = ${score.toFixed(1)}`,
    });
  });
}

/**
 * 综合优先级矩阵。
 *
 * @param {object[]} items
 * @param {string} itemType
 * @param {object} strategyPackage
 * @returns {{ priorities: object[], matrix: object }}
 */
export function buildPriorityMatrix(items, itemType, strategyPackage) {
  const moscow = prioritizeByMoSCoW(items, itemType, strategyPackage);
  const rice = prioritizeByRICE(items, itemType, strategyPackage);
  const wsjf = prioritizeByWSJF(items, itemType);

  // Merge: use MoSCoW as primary category
  const priorities = moscow.map((m, i) => ({
    ...m,
    scores: {
      moscow: m.score,
      rice: rice[i].score,
      wsjf: wsjf[i].score,
    },
  }));

  // Build matrix view
  const matrix = {
    mustHave: priorities.filter(p => p.category === PRIORITY_CATEGORY.MUST_HAVE).map(p => p.itemId),
    shouldHave: priorities.filter(p => p.category === PRIORITY_CATEGORY.SHOULD_HAVE).map(p => p.itemId),
    couldHave: priorities.filter(p => p.category === PRIORITY_CATEGORY.COULD_HAVE).map(p => p.itemId),
    wontHave: priorities.filter(p => p.category === PRIORITY_CATEGORY.WONT_HAVE).map(p => p.itemId),
    summary: {
      [PRIORITY_CATEGORY.MUST_HAVE]: priorities.filter(p => p.category === PRIORITY_CATEGORY.MUST_HAVE).length,
      [PRIORITY_CATEGORY.SHOULD_HAVE]: priorities.filter(p => p.category === PRIORITY_CATEGORY.SHOULD_HAVE).length,
      [PRIORITY_CATEGORY.COULD_HAVE]: priorities.filter(p => p.category === PRIORITY_CATEGORY.COULD_HAVE).length,
      [PRIORITY_CATEGORY.WONT_HAVE]: priorities.filter(p => p.category === PRIORITY_CATEGORY.WONT_HAVE).length,
    },
  };

  return { priorities, matrix };
}

// ═══════════════════════════════════════════════════════
// MVP Generator (Part N)
// ═══════════════════════════════════════════════════════

/**
 * 从 Roadmap + Priority 自动生成 MVP Scope。
 *
 * 确保 SF-01 Roadmap ↓ SF-02 Scope 完全一致。
 *
 * @param {object} opts
 * @param {object} opts.strategyPackage  — SF-01 Strategy Package
 * @param {object[]} opts.epicPriorities
 * @param {object[]} opts.featurePriorities
 * @param {object[]} opts.storyPriorities
 * @param {object[]} opts.epics
 * @param {object[]} opts.features
 * @param {object[]} opts.userStories
 * @returns {object} MVP Scope
 */
export function generateMVPScope({
  strategyPackage, epicPriorities = [], featurePriorities = [],
  storyPriorities = [], epics = [], features = [], userStories = [],
}) {
  const roadmap = strategyPackage?.roadmap || {};

  /**
   * Filter items by priority category.
   */
  const filterByPriority = (items, priorities, ids, label) => {
    const mustIds = new Set(
      priorities.filter(p => p.category === PRIORITY_CATEGORY.MUST_HAVE).map(p => p.itemId)
    );
    const shouldIds = new Set(
      priorities.filter(p => p.category === PRIORITY_CATEGORY.SHOULD_HAVE).map(p => p.itemId)
    );
    const couldIds = new Set(
      priorities.filter(p => p.category === PRIORITY_CATEGORY.COULD_HAVE).map(p => p.itemId)
    );

    return {
      mvp: ids.filter(id => mustIds.has(id)),
      v1: ids.filter(id => mustIds.has(id) || shouldIds.has(id)),
      v2: ids.filter(id => mustIds.has(id) || shouldIds.has(id) || couldIds.has(id)),
    };
  };

  const epicScope = filterByPriority(epics, epicPriorities, epics.map(e => e.id));
  const featureScope = filterByPriority(features, featurePriorities, features.map(f => f.id));
  const storyScope = filterByPriority(userStories, storyPriorities, userStories.map(s => s.id));

  const mvpMustStories = userStories.filter(s => storyScope.mvp.includes(s.id));

  return {
    // ─── 来自 SF-01 Roadmap 的阶段定义 ───
    phases: (roadmap.phases || []).map(p => ({
      name: p.phase || p.name || "",
      scope: p.scope || "",
      duration: p.durationMonths || p.duration || 0,
      budget: p.budget || 0,
    })),

    // ─── MVP Scope (Must Have only) ───
    mvp: {
      label: "MVP",
      description: roadmap.phases?.find(p => p.phase === "mvp")?.scope || "最小可行产品",
      epics: epicScope.mvp.length,
      features: featureScope.mvp.length,
      userStories: storyScope.mvp.length,
      totalStoryPoints: mvpMustStories.reduce((sum, s) => sum + (s.storyPoints || 0), 0),
      mustHaveStories: mvpMustStories,
    },

    // ─── V1 Scope (Must Have + Should Have) ───
    v1: {
      label: "V1",
      description: roadmap.phases?.find(p => p.phase === "v1")?.scope || "第一个完整版本",
      epics: epicScope.v1.length,
      features: featureScope.v1.length,
      userStories: storyScope.v1.length,
      totalStoryPoints: userStories.filter(s => storyScope.v1.includes(s.id)).reduce((sum, s) => sum + (s.storyPoints || 0), 0),
    },

    // ─── V2 Scope (Must + Should + Could) ───
    v2: {
      label: "V2",
      description: roadmap.phases?.find(p => p.phase === "v2")?.scope || "功能增强版本",
      epics: epicScope.v2.length,
      features: featureScope.v2.length,
      userStories: storyScope.v2.length,
      totalStoryPoints: userStories.filter(s => storyScope.v2.includes(s.id)).reduce((sum, s) => sum + (s.storyPoints || 0), 0),
    },

    // ─── Enterprise / Global Scope ───
    enterprise: {
      label: "Enterprise",
      description: roadmap.phases?.find(p => p.phase === "enterprise")?.scope || "企业版增强功能",
      epics: epics.length,
      features: features.length,
      userStories: userStories.length,
    },
    global: {
      label: "Global",
      description: roadmap.phases?.find(p => p.phase === "global")?.scope || "全球化版本",
      epics: epics.length,
      features: features.length,
      userStories: userStories.length,
    },
  };
}

// ═══════════════════════════════════════════════════════
// Traceability Engine (Part O)
// ═══════════════════════════════════════════════════════

import { createTraceabilityLink, LINK_TYPE } from "./domain-model.mjs";

/**
 * 构建从 Strategy → Epic → Feature → Story → AC 的完整追踪矩阵。
 *
 * @param {object} opts
 * @param {object[]} opts.epics
 * @param {object[]} opts.features
 * @param {object[]} opts.userStories
 * @param {object[]} opts.acceptanceCriteria
 * @param {object[]} opts.businessRules
 * @param {object[]} opts.nonFunctionalReqs
 * @param {object[]} opts.permissionReqs
 * @param {object[]} opts.integrationReqs
 * @param {object[]} opts.dataReqs
 * @returns {{ links: object[], matrix: object }}
 */
export function buildTraceabilityMatrix({
  epics = [], features = [], userStories = [],
  acceptanceCriteria = [], businessRules = [],
  nonFunctionalReqs = [], permissionReqs = [],
  integrationReqs = [], dataReqs = [],
}) {
  const links = [];

  // ── 1. Strategy → Epic ──
  for (const epic of epics) {
    links.push(createTraceabilityLink({
      sourceId: "SF-01", sourceType: "factory",
      targetId: epic.id, targetType: "epic",
      linkType: LINK_TYPE.STRATEGY_TO_EPIC,
      description: `${epic.title} 来源于产品战略分析`,
    }));
  }

  // ── 2. Epic → Feature ──
  for (const feature of features) {
    links.push(createTraceabilityLink({
      sourceId: feature.epicId, sourceType: "epic",
      targetId: feature.id, targetType: "feature",
      linkType: LINK_TYPE.EPIC_TO_FEATURE,
      description: `${feature.title} 属于 ${feature.epicId} 史诗`,
    }));
  }

  // ── 3. Feature → Story ──
  for (const story of userStories) {
    links.push(createTraceabilityLink({
      sourceId: story.featureId, sourceType: "feature",
      targetId: story.id, targetType: "story",
      linkType: LINK_TYPE.FEATURE_TO_STORY,
      description: `${story.statement} 源自 ${story.featureId}`,
    }));
  }

  // ── 4. Story → Acceptance Criteria ──
  for (const ac of acceptanceCriteria) {
    links.push(createTraceabilityLink({
      sourceId: ac.storyId, sourceType: "story",
      targetId: ac.id, targetType: "acceptance-criteria",
      linkType: LINK_TYPE.STORY_TO_AC,
      description: `AC #${ac.order}: ${ac.scenario || "untitled"}`,
    }));
  }

  // ── 5. Story → Business Rule ──
  for (const br of businessRules) {
    const relevantEpicIds = br.relatedEpics || [];
    for (const eid of relevantEpicIds) {
      const epicFeatures = features.filter(f => f.epicId === eid);
      for (const ft of epicFeatures) {
        const stories = userStories.filter(s => s.featureId === ft.id).slice(0, 2);
        for (const story of stories) {
          links.push(createTraceabilityLink({
            sourceId: story.id, sourceType: "story",
            targetId: br.id, targetType: "business-rule",
            linkType: LINK_TYPE.STORY_TO_BUSINESS_RULE,
            description: `${br.name} 适用于 ${story.statement}`,
          }));
        }
      }
    }
  }

  // ── 6. Story → NFR ──
  if (nonFunctionalReqs.length > 0) {
    // Link first few NFRs to first few stories for traceability
    for (let i = 0; i < Math.min(nonFunctionalReqs.length, 5); i++) {
      // All stories are affected by performance/security NFRs
      const sampleStories = userStories.slice(0, Math.min(3, userStories.length));
      for (const story of sampleStories) {
        links.push(createTraceabilityLink({
          sourceId: story.id, sourceType: "story",
          targetId: nonFunctionalReqs[i].id, targetType: "nfr",
          linkType: LINK_TYPE.STORY_TO_NFR,
          description: `${nonFunctionalReqs[i].name} 适用于所有操作场景`,
        }));
      }
    }
  }

  // ── 7. Epic → Permission ──
  if (permissionReqs) {
    links.push(createTraceabilityLink({
      sourceId: epics[0]?.id || "SF-02", sourceType: "epic",
      targetId: permissionReqs.id, targetType: "permission-requirement",
      linkType: LINK_TYPE.EPIC_TO_PERMISSION,
      description: `权限模型定义所有 Epic 的访问控制`,
    }));
  }

  // ── 8. Epic → Integration ──
  for (const ir of integrationReqs) {
    links.push(createTraceabilityLink({
      sourceId: epics[0]?.id || "SF-02", sourceType: "epic",
      targetId: ir.id, targetType: "integration-requirement",
      linkType: LINK_TYPE.EPIC_TO_INTEGRATION,
      description: `${ir.name} 集成需求`,
    }));
  }

  // ── 9. Story → Data ──
  if (dataReqs.length > 0 && userStories.length > 0) {
    // Link user stories to their relevant data requirements
    for (let i = 0; i < Math.min(dataReqs.length, 5); i++) {
      const sampleStories = userStories.slice(i * 3, (i + 1) * 3).filter(Boolean);
      for (const story of sampleStories) {
        links.push(createTraceabilityLink({
          sourceId: story.id, sourceType: "story",
          targetId: dataReqs[i].id, targetType: "data-requirement",
          linkType: LINK_TYPE.STORY_TO_DATA,
          description: `Story 操作涉及 ${dataReqs[i].entityName}`,
        }));
      }
    }
  }

  // ── Build Matrix ──
  const matrix = {
    strategyToEpic: links.filter(l => l.linkType === LINK_TYPE.STRATEGY_TO_EPIC).length,
    epicToFeature: links.filter(l => l.linkType === LINK_TYPE.EPIC_TO_FEATURE).length,
    featureToStory: links.filter(l => l.linkType === LINK_TYPE.FEATURE_TO_STORY).length,
    storyToAC: links.filter(l => l.linkType === LINK_TYPE.STORY_TO_AC).length,
    storyToBR: links.filter(l => l.linkType === LINK_TYPE.STORY_TO_BUSINESS_RULE).length,
    storyToNFR: links.filter(l => l.linkType === LINK_TYPE.STORY_TO_NFR).length,
    epicToPermission: links.filter(l => l.linkType === LINK_TYPE.EPIC_TO_PERMISSION).length,
    epicToIntegration: links.filter(l => l.linkType === LINK_TYPE.EPIC_TO_INTEGRATION).length,
    storyToData: links.filter(l => l.linkType === LINK_TYPE.STORY_TO_DATA).length,
    totalLinks: links.length,
    coverage: {
      epicsWithLinks: [...new Set(links.filter(l => l.sourceType === "epic").map(l => l.sourceId))].length,
      featuresWithLinks: [...new Set(links.filter(l => l.sourceType === "feature").map(l => l.sourceId))].length,
      storiesWithLinks: [...new Set(links.filter(l => l.sourceType === "story").map(l => l.sourceId))].length,
    },
  };

  return { links, matrix };
}
