import { v4 as uuidv4 } from "uuid";
import { logger } from "../monitoring/logger.js";
class ConflictDetector {
  SIMILARITY_THRESHOLD = 0.8;
  /**
   * Detect all types of conflicts between two frame stacks
   */
  detectConflicts(stack1, stack2) {
    const conflicts = [];
    const parallelConflicts = this.detectParallelSolutions(stack1, stack2);
    conflicts.push(...parallelConflicts);
    const decisionConflicts = this.detectConflictingDecisions(
      stack1.events,
      stack2.events
    );
    conflicts.push(...decisionConflicts);
    const structuralConflicts = this.detectStructuralDivergence(
      stack1.frames,
      stack2.frames
    );
    conflicts.push(...structuralConflicts);
    logger.info(`Detected ${conflicts.length} conflicts between stacks`, {
      stack1Id: stack1.id,
      stack2Id: stack2.id,
      conflictTypes: this.summarizeConflictTypes(conflicts)
    });
    return conflicts;
  }
  /**
   * Analyze frames to find parallel solutions to the same problem
   */
  analyzeParallelSolutions(frames) {
    const solutions = [];
    const groupedFrames = this.groupSimilarFrames(frames);
    for (const group of groupedFrames) {
      if (group.length > 1) {
        group.forEach((frame) => {
          solutions.push({
            frameId: frame.frame_id,
            solution: this.extractSolution(frame),
            approach: this.analyzeApproach(frame),
            author: frame.inputs?.author || "unknown",
            timestamp: frame.created_at,
            effectiveness: this.calculateEffectiveness(frame)
          });
        });
      }
    }
    return solutions;
  }
  /**
   * Identify conflicting decisions in event streams
   */
  identifyConflictingDecisions(events) {
    const conflicts = [];
    const decisions = this.extractDecisions(events);
    for (let i = 0; i < decisions.length; i++) {
      for (let j = i + 1; j < decisions.length; j++) {
        if (this.decisionsConflict(decisions[i], decisions[j])) {
          conflicts.push({
            decision1: decisions[i].payload?.decision || "",
            decision2: decisions[j].payload?.decision || "",
            impact: this.assessImpact(decisions[i], decisions[j]),
            canCoexist: this.canCoexist(decisions[i], decisions[j])
          });
        }
      }
    }
    return conflicts;
  }
  /**
   * Detect parallel solutions between two stacks
   */
  detectParallelSolutions(stack1, stack2) {
    const conflicts = [];
    for (const frame1 of stack1.frames) {
      for (const frame2 of stack2.frames) {
        if (this.framesAreSimilar(frame1, frame2) && !this.framesAreIdentical(frame1, frame2)) {
          conflicts.push({
            id: uuidv4(),
            type: "parallel_solution",
            frameId1: frame1.frame_id,
            frameId2: frame2.frame_id,
            severity: this.calculateParallelSeverity(frame1, frame2),
            description: `Parallel solutions detected: "${frame1.name}" vs "${frame2.name}"`,
            detectedAt: Date.now(),
            conflictingPaths: this.extractPaths(frame1, frame2)
          });
        }
      }
    }
    return conflicts;
  }
  /**
   * Detect conflicting decisions between event streams
   */
  detectConflictingDecisions(events1, events2) {
    const conflicts = [];
    const decisions1 = this.extractDecisions(events1);
    const decisions2 = this.extractDecisions(events2);
    for (const d1 of decisions1) {
      for (const d2 of decisions2) {
        if (this.decisionsConflict(d1, d2)) {
          conflicts.push({
            id: uuidv4(),
            type: "conflicting_decision",
            frameId1: d1.frame_id,
            frameId2: d2.frame_id,
            severity: this.assessImpact(d1, d2),
            description: `Conflicting decisions: "${d1.payload?.decision}" vs "${d2.payload?.decision}"`,
            detectedAt: Date.now()
          });
        }
      }
    }
    return conflicts;
  }
  /**
   * Detect structural divergence in frame hierarchies
   */
  detectStructuralDivergence(frames1, frames2) {
    const conflicts = [];
    const tree1 = this.buildFrameTree(frames1);
    const tree2 = this.buildFrameTree(frames2);
    const divergences = this.findDivergences(tree1, tree2);
    for (const divergence of divergences) {
      conflicts.push({
        id: uuidv4(),
        type: "structural_divergence",
        frameId1: divergence.node1,
        frameId2: divergence.node2,
        severity: this.calculateDivergenceSeverity(divergence),
        description: `Structural divergence at depth ${divergence.depth}`,
        detectedAt: Date.now()
      });
    }
    return conflicts;
  }
  /**
   * Helper: Check if two frames are similar (solving same problem)
   */
  framesAreSimilar(frame1, frame2) {
    const nameSimilarity = this.calculateSimilarity(frame1.name, frame2.name);
    if (nameSimilarity > this.SIMILARITY_THRESHOLD) return true;
    if (frame1.type === frame2.type && frame1.parent_frame_id === frame2.parent_frame_id) {
      return true;
    }
    const inputSimilarity = this.compareInputs(frame1.inputs, frame2.inputs);
    return inputSimilarity > this.SIMILARITY_THRESHOLD;
  }
  /**
   * Helper: Check if frames are identical
   */
  framesAreIdentical(frame1, frame2) {
    return frame1.frame_id === frame2.frame_id;
  }
  /**
   * Helper: Calculate string similarity (Levenshtein-based)
   */
  calculateSimilarity(str1, str2) {
    const maxLen = Math.max(str1.length, str2.length);
    if (maxLen === 0) return 1;
    const distance = this.levenshteinDistance(str1, str2);
    return 1 - distance / maxLen;
  }
  /**
   * Helper: Levenshtein distance implementation
   */
  levenshteinDistance(str1, str2) {
    const matrix = [];
    for (let i = 0; i <= str2.length; i++) {
      matrix[i] = [i];
    }
    for (let j = 0; j <= str1.length; j++) {
      matrix[0][j] = j;
    }
    for (let i = 1; i <= str2.length; i++) {
      for (let j = 1; j <= str1.length; j++) {
        if (str2.charAt(i - 1) === str1.charAt(j - 1)) {
          matrix[i][j] = matrix[i - 1][j - 1];
        } else {
          matrix[i][j] = Math.min(
            matrix[i - 1][j - 1] + 1,
            matrix[i][j - 1] + 1,
            matrix[i - 1][j] + 1
          );
        }
      }
    }
    return matrix[str2.length][str1.length];
  }
  /**
   * Helper: Compare frame inputs
   */
  compareInputs(inputs1, inputs2) {
    const keys1 = Object.keys(inputs1 || {});
    const keys2 = Object.keys(inputs2 || {});
    const allKeys = /* @__PURE__ */ new Set([...keys1, ...keys2]);
    if (allKeys.size === 0) return 1;
    let matches = 0;
    for (const key of allKeys) {
      if (JSON.stringify(inputs1[key]) === JSON.stringify(inputs2[key])) {
        matches++;
      }
    }
    return matches / allKeys.size;
  }
  /**
   * Helper: Calculate severity for parallel solutions
   */
  calculateParallelSeverity(frame1, frame2) {
    if (frame1.state === "closed" && frame2.state === "closed") {
      const outputSimilarity = this.compareInputs(
        frame1.outputs,
        frame2.outputs
      );
      if (outputSimilarity < 0.5) return "critical";
      if (outputSimilarity < 0.7) return "high";
    }
    if (frame1.parent_frame_id === frame2.parent_frame_id) {
      return "high";
    }
    return "medium";
  }
  /**
   * Helper: Extract decision events
   */
  extractDecisions(events) {
    return events.filter(
      (e) => e.event_type === "decision" || e.payload?.type === "decision" || e.payload?.decision !== void 0
    );
  }
  /**
   * Helper: Check if two decisions conflict
   */
  decisionsConflict(d1, d2) {
    const resource1 = d1.payload?.resource || d1.payload?.path;
    const resource2 = d2.payload?.resource || d2.payload?.path;
    if (resource1 && resource2 && resource1 === resource2) {
      return d1.payload?.decision !== d2.payload?.decision;
    }
    return this.hasLogicalConflict(d1.payload, d2.payload);
  }
  /**
   * Helper: Check for logical conflicts in payloads
   */
  hasLogicalConflict(payload1, payload2) {
    if (payload1?.architecture && payload2?.architecture) {
      return payload1.architecture !== payload2.architecture;
    }
    if (payload1?.technology && payload2?.technology) {
      return payload1.technology !== payload2.technology;
    }
    return false;
  }
  /**
   * Helper: Assess impact of conflicting decisions
   */
  assessImpact(d1, d2) {
    if (d1.payload?.type === "architecture" || d2.payload?.type === "architecture") {
      return "high";
    }
    if (d1.payload?.scope === "implementation" || d2.payload?.scope === "implementation") {
      return "medium";
    }
    return "low";
  }
  /**
   * Helper: Check if decisions can coexist
   */
  canCoexist(d1, d2) {
    if (d1.payload?.scope !== d2.payload?.scope) {
      return true;
    }
    const resource1 = d1.payload?.resource;
    const resource2 = d2.payload?.resource;
    return resource1 !== resource2;
  }
  /**
   * Helper: Build frame tree structure
   */
  buildFrameTree(frames) {
    const tree = /* @__PURE__ */ new Map();
    for (const frame of frames) {
      if (frame.parent_frame_id) {
        if (!tree.has(frame.parent_frame_id)) {
          tree.set(frame.parent_frame_id, /* @__PURE__ */ new Set());
        }
        const parentSet = tree.get(frame.parent_frame_id);
        if (parentSet) {
          parentSet.add(frame.frame_id);
        }
      }
    }
    return tree;
  }
  /**
   * Helper: Find divergence points in trees
   */
  findDivergences(tree1, tree2) {
    const divergences = [];
    for (const [node, children1] of tree1) {
      if (tree2.has(node)) {
        const children2 = tree2.get(node);
        if (children2 && !this.setsEqual(children1, children2)) {
          divergences.push({
            node1: node,
            node2: node,
            depth: this.calculateDepth(node, tree1)
          });
        }
      }
    }
    return divergences;
  }
  /**
   * Helper: Check if two sets are equal
   */
  setsEqual(set1, set2) {
    if (set1.size !== set2.size) return false;
    for (const item of set1) {
      if (!set2.has(item)) return false;
    }
    return true;
  }
  /**
   * Helper: Calculate node depth in tree
   */
  calculateDepth(node, tree) {
    let depth = 0;
    let current = node;
    for (const [parent, children] of tree) {
      if (children.has(current)) {
        depth++;
        current = parent;
      }
    }
    return depth;
  }
  /**
   * Helper: Calculate divergence severity
   */
  calculateDivergenceSeverity(divergence) {
    if (divergence.depth === 0) return "critical";
    if (divergence.depth === 1) return "high";
    if (divergence.depth === 2) return "medium";
    return "low";
  }
  /**
   * Helper: Extract paths from frames
   */
  extractPaths(frame1, frame2) {
    const paths = [];
    if (frame1.inputs?.path) paths.push(frame1.inputs.path);
    if (frame2.inputs?.path) paths.push(frame2.inputs.path);
    if (frame1.outputs?.files) paths.push(...frame1.outputs.files);
    if (frame2.outputs?.files) paths.push(...frame2.outputs.files);
    return [...new Set(paths)];
  }
  /**
   * Helper: Extract solution from frame
   */
  extractSolution(frame) {
    return frame.outputs?.solution || frame.digest_text || "No solution description";
  }
  /**
   * Helper: Analyze approach taken
   */
  analyzeApproach(frame) {
    if (frame.outputs?.approach) return frame.outputs.approach;
    if (frame.type === "debug") return "Debug approach";
    if (frame.type === "review") return "Review approach";
    return "Standard approach";
  }
  /**
   * Helper: Calculate solution effectiveness
   */
  calculateEffectiveness(frame) {
    let score = 0.5;
    if (frame.state === "closed") score += 0.2;
    if (frame.outputs && Object.keys(frame.outputs).length > 0) score += 0.1;
    if (frame.digest_text) score += 0.1;
    if (frame.closed_at && frame.created_at) {
      const duration = frame.closed_at - frame.created_at;
      if (duration < 3e5) score += 0.1;
    }
    return Math.min(score, 1);
  }
  /**
   * Helper: Group similar frames together
   */
  groupSimilarFrames(frames) {
    const groups = [];
    const processed = /* @__PURE__ */ new Set();
    for (const frame of frames) {
      if (processed.has(frame.frame_id)) continue;
      const group = [frame];
      processed.add(frame.frame_id);
      for (const other of frames) {
        if (!processed.has(other.frame_id) && this.framesAreSimilar(frame, other)) {
          group.push(other);
          processed.add(other.frame_id);
        }
      }
      groups.push(group);
    }
    return groups;
  }
  /**
   * Helper: Summarize conflict types
   */
  summarizeConflictTypes(conflicts) {
    const summary = {
      parallel_solution: 0,
      conflicting_decision: 0,
      structural_divergence: 0
    };
    for (const conflict of conflicts) {
      summary[conflict.type]++;
    }
    return summary;
  }
}
export {
  ConflictDetector
};
//# sourceMappingURL=conflict-detector.js.map
