/**
 * Software Factory Core — Artifact Graph
 *
 * PR-36 Part E：统一产物图谱，追踪全流程产物及其关系。
 *
 * 支持：
 *   - 需求文档 / 原型图 / 设计稿 / 架构图 / 代码 / 测试 / 发布包 / 运维报告 / 营销资料
 *   - 血缘追踪（parent → child）
 *   - 依赖追踪（artifact A depends on artifact B）
 *   - 版本管理
 *   - 按 Factory / Product / Kind 检索
 *   - 完整性校验（checksum）
 *
 * 与 PR-35 ArtifactRegistry 的关系：
 *   此 ArtifactGraph 扩展自 PR-35 的 ArtifactRegistry，
 *   额外增加图遍历、血缘查询、依赖分析等能力。
 *
 * @module software-factory-core/artifact-graph
 * @since PR-36
 */

import { FACTORY_ARTIFACT_KIND } from "./factory-contract.mjs";

// ═══════════════════════════════════════════════════════
// ArtifactNode — 图节点
// ═══════════════════════════════════════════════════════

let _anSeq = 0;

/**
 * Artifact 图节点。
 *
 * @param {object} p
 * @param {string} [p.id]
 * @param {string} p.kind            — FACTORY_ARTIFACT_KIND
 * @param {string} p.name
 * @param {string} p.factoryId       — 产出的 Factory
 * @param {string|null} [p.productId=null]
 * @param {number} [p.version=1]
 * @param {string|null} [p.path=null]
 * @param {string|null} [p.content=null]
 * @param {object} [p.metadata={}]
 * @returns {object} ArtifactNode
 */
export function createArtifactNode({
  id,
  kind,
  name,
  factoryId,
  productId = null,
  version = 1,
  path = null,
  content = null,
  metadata = {},
}) {
  if (!kind || !FACTORY_ARTIFACT_KIND[kind.toUpperCase()]) {
    throw new TypeError(`Invalid artifact kind: ${kind}`);
  }
  if (!name) throw new TypeError("ArtifactNode.name is required");
  if (!factoryId) throw new TypeError("ArtifactNode.factoryId is required");

  return {
    id: id || `an-${++_anSeq}`,
    kind,
    name,
    factoryId,
    productId,
    version,
    path,
    content,
    metadata: { ...metadata },
    checksum: null, // set on registration
    createdAt: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// ArtifactEdge — 图边
// ═══════════════════════════════════════════════════════

/**
 * 边缘关系类型。
 */
export const EDGE_RELATION = Object.freeze({
  DEPENDS_ON:   "depends_on",    // A 依赖于 B
  PRODUCES:     "produces",      // Factory 产出 Artifact
  PARENT_OF:    "parent_of",     // A 是 B 的父版本
  DERIVED_FROM: "derived_from",  // A 由 B 派生
  REFERENCES:   "references",    // A 引用 B
  CONTAINS:     "contains",      // A 包含 B
  INPUT_TO:     "input_to",      // A 是 B 的输入
  RELATED_TO:   "related_to",    // 一般关联
});

let _aeSeq = 0;

/**
 * Artifact 图边。
 *
 * @param {object} p
 * @param {string} [p.id]
 * @param {string} p.from           — 源节点 ID
 * @param {string} p.to             — 目标节点 ID
 * @param {"depends_on"|"produces"|"parent_of"|"derived_from"|"references"|"contains"|"input_to"|"related_to"} p.relation
 * @param {object} [p.metadata={}]
 * @returns {object} ArtifactEdge
 */
export function createArtifactEdge({
  id,
  from,
  to,
  relation,
  metadata = {},
}) {
  if (!from) throw new TypeError("ArtifactEdge.from is required");
  if (!to) throw new TypeError("ArtifactEdge.to is required");
  if (!EDGE_RELATION[relation?.toUpperCase()]) throw new TypeError(`Invalid edge relation: ${relation}`);

  return {
    id: id || `ae-${++_aeSeq}`,
    from,
    to,
    relation,
    metadata: { ...metadata },
    createdAt: new Date().toISOString(),
  };
}

// ═══════════════════════════════════════════════════════
// ArtifactGraph
// ═══════════════════════════════════════════════════════

/**
 * 产物图谱实例。
 *
 * 提供：
 *   - 产物注册 / 检索
 *   - 图遍历（祖先、后代、依赖链）
 *   - 完整性校验
 *   - 按维度统计
 *
 * Usage:
 *   const graph = createArtifactGraph();
 *   graph.addNode(node);
 *   graph.addEdge(edge);
 *   graph.getAncestors(nodeId);
 *   graph.getDependencyChain(nodeId);
 *
 * @returns {object} ArtifactGraph
 */
export function createArtifactGraph() {
  /** @type {Map<string, object>} id → ArtifactNode */
  const _nodes = new Map();

  /** @type {Map<string, object>} id → ArtifactEdge */
  const _edges = new Map();

  /** @type {Map<string, Set<string>>} nodeId → Set<edgeId> (outgoing) */
  const _outEdges = new Map();

  /** @type {Map<string, Set<string>>} nodeId → Set<edgeId> (incoming) */
  const _inEdges = new Map();

  /** @type {Map<string, string[]>} factoryId → nodeIds */
  const _byFactory = new Map();

  /** @type {Map<string, string[]>} kind → nodeIds */
  const _byKind = new Map();

  /** @type {Map<string, string[]>} productId → nodeIds */
  const _byProduct = new Map();

  const self = {
    addNode, addEdge, getNode, getEdge,
    findByFactory, findByKind, findByProduct,
    getAncestors, getDescendants, getDependencyChain,
    getDirectDependencies, getDirectDependents,
    list, count, stats,
    validateAll, validateNode,
    clear,
  };

  // ═══════════════════════════════════════════════════
  // Node Operations
  // ═══════════════════════════════════════════════════

  /**
   * 添加产物节点。
   * @param {object} node — ArtifactNode
   * @returns {object} { id, stored }
   */
  function addNode(node) {
    if (!node?.id) throw new TypeError("ArtifactNode.id is required");

    // checksum
    const content = node.content || JSON.stringify(node.metadata || {});
    node.checksum = _simpleHash(content);

    // 版本
    if (_nodes.has(node.id)) {
      const existing = _nodes.get(node.id);
      node.version = (existing.version || 1) + 1;
    }

    _nodes.set(node.id, { ...node });

    // 索引
    if (node.factoryId) {
      if (!_byFactory.has(node.factoryId)) _byFactory.set(node.factoryId, []);
      const list = _byFactory.get(node.factoryId);
      if (!list.includes(node.id)) list.push(node.id);
    }

    if (node.kind) {
      if (!_byKind.has(node.kind)) _byKind.set(node.kind, []);
      const list = _byKind.get(node.kind);
      if (!list.includes(node.id)) list.push(node.id);
    }

    if (node.productId) {
      if (!_byProduct.has(node.productId)) _byProduct.set(node.productId, []);
      const list = _byProduct.get(node.productId);
      if (!list.includes(node.id)) list.push(node.id);
    }

    return { id: node.id, stored: true, version: node.version };
  }

  /**
   * 获取产物节点。
   * @param {string} id
   * @returns {object|null}
   */
  function getNode(id) {
    return _nodes.get(id) || null;
  }

  // ═══════════════════════════════════════════════════
  // Edge Operations
  // ═══════════════════════════════════════════════════

  /**
   * 添加边。
   * @param {object} edge — ArtifactEdge
   * @returns {object} { id, stored }
   */
  function addEdge(edge) {
    if (!edge?.id) throw new TypeError("ArtifactEdge.id is required");

    // 验证节点存在
    if (!_nodes.has(edge.from)) {
      throw new Error(`Edge references unknown source node: ${edge.from}`);
    }
    if (!_nodes.has(edge.to)) {
      throw new Error(`Edge references unknown target node: ${edge.to}`);
    }

    _edges.set(edge.id, { ...edge });

    // 邻接索引
    if (!_outEdges.has(edge.from)) _outEdges.set(edge.from, new Set());
    _outEdges.get(edge.from).add(edge.id);

    if (!_inEdges.has(edge.to)) _inEdges.set(edge.to, new Set());
    _inEdges.get(edge.to).add(edge.id);

    return { id: edge.id, stored: true };
  }

  /**
   * 获取边。
   * @param {string} id
   * @returns {object|null}
   */
  function getEdge(id) {
    return _edges.get(id) || null;
  }

  // ═══════════════════════════════════════════════════
  // Queries
  // ═══════════════════════════════════════════════════

  /** @param {string} factoryId */
  function findByFactory(factoryId) {
    const ids = _byFactory.get(factoryId) || [];
    return ids.map(id => _nodes.get(id)).filter(Boolean);
  }

  /** @param {string} kind */
  function findByKind(kind) {
    const ids = _byKind.get(kind) || [];
    return ids.map(id => _nodes.get(id)).filter(Boolean);
  }

  /** @param {string} productId */
  function findByProduct(productId) {
    const ids = _byProduct.get(productId) || [];
    return ids.map(id => _nodes.get(id)).filter(Boolean);
  }

  /** @param {object} [opts] */
  function list(opts = {}) {
    let result = [..._nodes.values()];
    if (opts.kind) result = result.filter(n => n.kind === opts.kind);
    if (opts.factoryId) result = result.filter(n => n.factoryId === opts.factoryId);
    if (opts.productId) result = result.filter(n => n.productId === opts.productId);
    return result;
  }

  function count(opts = {}) {
    return self.list(opts).length;
  }

  // ═══════════════════════════════════════════════════
  // Graph Traversal
  // ═══════════════════════════════════════════════════

  /**
   * 获取祖先节点（沿 outgoing depends_on / derived_from / parent_of 追溯）。
   *
   * Edge 语义：from=A, to=B, relation=depends_on 表示"A 依赖 B"。
   * 所以追溯 A 的祖先 = 沿着 A 的 outgoing depends_on 边 → B → B 的 outgoing → ...
   *
   * @param {string} nodeId
   * @param {number} [maxDepth=10]
   * @returns {object[]}
   */
  function getAncestors(nodeId, maxDepth = 10) {
    const result = [];
    const visited = new Set();
    _traverseUp(nodeId, visited, result, maxDepth, 0);
    return result;
  }

  function _traverseUp(nodeId, visited, result, maxDepth, depth) {
    if (depth >= maxDepth || visited.has(nodeId)) return;
    visited.add(nodeId);

    const outgoing = _outEdges.get(nodeId);
    if (!outgoing) return;

    for (const edgeId of outgoing) {
      const edge = _edges.get(edgeId);
      if (!edge) continue;

      // depends_on / derived_from / parent_of edges: follow to the dependency
      const relevantRelations = [
        EDGE_RELATION.DEPENDS_ON,
        EDGE_RELATION.DERIVED_FROM,
        EDGE_RELATION.PARENT_OF,
      ];
      if (!relevantRelations.includes(edge.relation)) continue;

      const targetNode = _nodes.get(edge.to);
      if (targetNode) {
        result.push(targetNode);
        _traverseUp(edge.to, visited, result, maxDepth, depth + 1);
      }
    }
  }

  /**
   * 获取后代节点（沿 incoming depends_on 正向追溯：谁依赖我）。
   *
   * Edge 语义：from=A, to=B, relation=depends_on 表示"A 依赖 B"。
   * 所以追溯 B 的后代 = 沿着 B 的 incoming depends_on 边 → 找到依赖 B 的节点 → 递归。
   *
   * @param {string} nodeId
   * @param {number} [maxDepth=10]
   * @returns {object[]}
   */
  function getDescendants(nodeId, maxDepth = 10) {
    const result = [];
    const visited = new Set();
    _traverseDown(nodeId, visited, result, maxDepth, 0);
    return result;
  }

  function _traverseDown(nodeId, visited, result, maxDepth, depth) {
    if (depth >= maxDepth || visited.has(nodeId)) return;
    visited.add(nodeId);

    const incoming = _inEdges.get(nodeId);
    if (!incoming) return;

    for (const edgeId of incoming) {
      const edge = _edges.get(edgeId);
      if (!edge) continue;

      // 谁依赖我？→ 找 incoming depends_on / derived_from 边的 from 节点
      const relevantRelations = [
        EDGE_RELATION.DEPENDS_ON,
        EDGE_RELATION.DERIVED_FROM,
        EDGE_RELATION.PARENT_OF,
        EDGE_RELATION.CONTAINS,
      ];
      if (!relevantRelations.includes(edge.relation)) continue;

      const sourceNode = _nodes.get(edge.from);
      if (sourceNode) {
        result.push(sourceNode);
        _traverseDown(edge.from, visited, result, maxDepth, depth + 1);
      }
    }
  }

  /**
   * 获取依赖链（从当前节点沿着 outgoing depends_on 追溯所有祖先）。
   * 返回拓扑排序的依赖列表（从根到叶）。
   *
   * Edge 语义：from=A, to=B, relation=depends_on 表示"A 依赖 B"。
   * 所以追溯 A 的依赖链 = A → A 的 outgoing depends_on 的 to 节点 → 递归。
   *
   * @param {string} nodeId
   * @returns {object[]}
   */
  function getDependencyChain(nodeId) {
    const result = [];
    const visited = new Set();

    function visit(nid) {
      if (visited.has(nid)) return;
      visited.add(nid);

      // 先访问 outgoing depends_on 的 target（依赖项），再访问自身
      const outgoing = _outEdges.get(nid);
      if (outgoing) {
        for (const edgeId of outgoing) {
          const edge = _edges.get(edgeId);
          if (edge && edge.relation === EDGE_RELATION.DEPENDS_ON) {
            visit(edge.to);
          }
        }
      }

      const node = _nodes.get(nid);
      if (node) result.push(node);
    }

    visit(nodeId);
    return result;
  }

  /**
   * 获取直接依赖（我依赖谁）。
   *
   * Edge 语义：from=A, to=B, relation=depends_on 表示"A 依赖 B"。
   * 所以 A 的直接依赖 = A 的 outgoing depends_on 边的 to 节点。
   *
   * @param {string} nodeId
   * @returns {object[]}
   */
  function getDirectDependencies(nodeId) {
    const outgoing = _outEdges.get(nodeId);
    if (!outgoing) return [];

    const deps = [];
    for (const edgeId of outgoing) {
      const edge = _edges.get(edgeId);
      if (edge && edge.relation === EDGE_RELATION.DEPENDS_ON) {
        const node = _nodes.get(edge.to);
        if (node) deps.push(node);
      }
    }
    return deps;
  }

  /**
   * 获取直接依赖者（谁依赖我）。
   *
   * Edge 语义：from=A, to=B, relation=depends_on 表示"A 依赖 B"。
   * 所以 B 的依赖者 = B 的 incoming depends_on 边的 from 节点。
   *
   * @param {string} nodeId
   * @returns {object[]}
   */
  function getDirectDependents(nodeId) {
    const incoming = _inEdges.get(nodeId);
    if (!incoming) return [];

    const deps = [];
    for (const edgeId of incoming) {
      const edge = _edges.get(edgeId);
      if (edge && edge.relation === EDGE_RELATION.DEPENDS_ON) {
        const node = _nodes.get(edge.from);
        if (node) deps.push(node);
      }
    }
    return deps;
  }

  // ═══════════════════════════════════════════════════
  // Validation
  // ═══════════════════════════════════════════════════

  /**
   * 验证单个节点完整性。
   * @param {string} nodeId
   * @returns {object} { valid, checksum, issues }
   */
  function validateNode(nodeId) {
    const node = _nodes.get(nodeId);
    if (!node) return { valid: false, nodeId, issues: ["Node not found"] };

    const issues = [];

    // 检查必需字段
    if (!node.kind) issues.push("Missing kind");
    if (!node.name) issues.push("Missing name");
    if (!node.factoryId) issues.push("Missing factoryId");

    // 检查 checksum 一致性
    const content = node.content || JSON.stringify(node.metadata || {});
    const expectedChecksum = _simpleHash(content);
    if (node.checksum && node.checksum !== expectedChecksum) {
      issues.push(`Checksum mismatch: expected ${expectedChecksum}, got ${node.checksum}`);
    }

    return {
      valid: issues.length === 0,
      nodeId,
      checksum: node.checksum,
      issues,
    };
  }

  /**
   * 验证所有节点。
   * @returns {object} { valid, total, passed, failed, results }
   */
  function validateAll() {
    const results = [];
    let passed = 0;
    let failed = 0;

    for (const node of _nodes.values()) {
      const r = self.validateNode(node.id);
      results.push(r);
      if (r.valid) passed++;
      else failed++;
    }

    return {
      valid: failed === 0,
      total: results.length,
      passed,
      failed,
      results,
    };
  }

  // ═══════════════════════════════════════════════════
  // Stats
  // ═══════════════════════════════════════════════════

  function stats() {
    const kindStats = {};
    for (const node of _nodes.values()) {
      kindStats[node.kind] = (kindStats[node.kind] || 0) + 1;
    }

    const relationStats = {};
    for (const edge of _edges.values()) {
      relationStats[edge.relation] = (relationStats[edge.relation] || 0) + 1;
    }

    return {
      totalNodes: _nodes.size,
      totalEdges: _edges.size,
      byKind: kindStats,
      byRelation: relationStats,
      byFactory: [..._byFactory.entries()].reduce((acc, [k, v]) => { acc[k] = v.length; return acc; }, {}),
    };
  }

  // ═══════════════════════════════════════════════════
  // Clear
  // ═══════════════════════════════════════════════════

  function clear() {
    _nodes.clear();
    _edges.clear();
    _outEdges.clear();
    _inEdges.clear();
    _byFactory.clear();
    _byKind.clear();
    _byProduct.clear();
  }

  return self;
}

// ─── Simple Hash ────────────────────────────────────

function _simpleHash(str) {
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    const char = str.charCodeAt(i);
    hash = ((hash << 5) - hash) + char;
    hash |= 0;
  }
  return hash.toString(16);
}
