import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import { v4 as uuidv4 } from "uuid";
import { ConflictDetector } from "./conflict-detector.js";
import { StackDiffVisualizer } from "./stack-diff.js";
import { logger } from "../monitoring/logger.js";
class ResolutionEngine {
  conflictDetector;
  diffVisualizer;
  resolutionHistory = /* @__PURE__ */ new Map();
  constructor() {
    this.conflictDetector = new ConflictDetector();
    this.diffVisualizer = new StackDiffVisualizer();
  }
  /**
   * Resolve conflicts using the specified strategy
   */
  async resolveConflicts(stack1, stack2, strategy, context) {
    const conflicts = this.conflictDetector.detectConflicts(stack1, stack2);
    logger.info(
      `Resolving ${conflicts.length} conflicts using ${strategy} strategy`,
      {
        userId: context.userId,
        userRole: context.userRole
      }
    );
    let resolution;
    switch (strategy) {
      case "keep_both":
        resolution = await this.keepBothStrategy(
          conflicts,
          stack1,
          stack2,
          context
        );
        break;
      case "team_vote":
        resolution = await this.teamVoteStrategy(
          conflicts,
          stack1,
          stack2,
          context
        );
        break;
      case "senior_override":
        resolution = await this.seniorOverrideStrategy(
          conflicts,
          stack1,
          stack2,
          context
        );
        break;
      case "ai_suggest":
        resolution = await this.aiSuggestStrategy(
          conflicts,
          stack1,
          stack2,
          context
        );
        break;
      case "hybrid":
        resolution = await this.hybridStrategy(
          conflicts,
          stack1,
          stack2,
          context
        );
        break;
      default:
        throw new Error(`Unknown resolution strategy: ${strategy}`);
    }
    const mergeResult = await this.executeMerge(
      stack1,
      stack2,
      conflicts,
      resolution
    );
    this.storeResolution(mergeResult.mergedFrameId || "", resolution);
    return mergeResult;
  }
  /**
   * Strategy: Keep Both Solutions
   * Creates a merged frame that includes both approaches
   */
  async keepBothStrategy(conflicts, stack1, stack2, context) {
    logger.info("Applying keep_both strategy");
    const strategy = {
      type: "keep_both",
      confidence: 0.8,
      reasoning: "Preserving both solutions to maintain all work and allow future evaluation"
    };
    for (const conflict of conflicts) {
      conflict.resolution = {
        strategy,
        resolvedBy: context.userId,
        resolvedAt: Date.now(),
        notes: "Both solutions preserved in merged frame"
      };
    }
    return {
      strategy,
      resolvedBy: context.userId,
      resolvedAt: Date.now(),
      notes: `Kept all ${stack1.frames.length + stack2.frames.length} frames from both stacks`
    };
  }
  /**
   * Strategy: Team Vote
   * Uses democratic voting to choose between options
   */
  async teamVoteStrategy(conflicts, stack1, stack2, context) {
    logger.info("Applying team_vote strategy");
    if (!context.teamVotes || context.teamVotes.length === 0) {
      throw new Error("Team vote strategy requires votes from team members");
    }
    const voteResults = this.countVotes(context.teamVotes);
    const strategy = {
      type: "team_vote",
      confidence: this.calculateVoteConfidence(voteResults),
      reasoning: `Team consensus from ${context.teamVotes.length} votes`,
      votes: context.teamVotes
    };
    for (const conflict of conflicts) {
      conflict.resolution = {
        strategy,
        resolvedBy: "team_consensus",
        resolvedAt: Date.now(),
        notes: `Resolved by ${voteResults.consensus}% consensus`
      };
    }
    return {
      strategy,
      resolvedBy: "team_consensus",
      resolvedAt: Date.now(),
      notes: `Democratic resolution with ${voteResults.consensus}% agreement`
    };
  }
  /**
   * Strategy: Senior Override
   * Senior developer's choice takes precedence
   */
  async seniorOverrideStrategy(conflicts, stack1, stack2, context) {
    logger.info("Applying senior_override strategy");
    if (context.userRole !== "senior" && context.userRole !== "lead") {
      throw new Error("Senior override requires senior or lead role");
    }
    this.determinePreferredStack(stack1, stack2, context);
    const strategy = {
      type: "senior_override",
      confidence: 0.95,
      reasoning: `Senior developer (${context.userId}) selected based on experience and architectural knowledge`
    };
    for (const conflict of conflicts) {
      conflict.resolution = {
        strategy,
        resolvedBy: context.userId,
        resolvedAt: Date.now(),
        notes: `Overridden by ${context.userRole} authority`
      };
    }
    return {
      strategy,
      resolvedBy: context.userId,
      resolvedAt: Date.now(),
      notes: `Senior override applied to all ${conflicts.length} conflicts`
    };
  }
  /**
   * Strategy: AI Suggest
   * Uses AI analysis to recommend best resolution
   */
  async aiSuggestStrategy(conflicts, stack1, stack2, context) {
    logger.info("Applying ai_suggest strategy");
    const analysis = await this.analyzeFrameQuality(stack1, stack2);
    const strategy = {
      type: "ai_suggest",
      confidence: context.aiConfidence || 0.85,
      reasoning: this.generateAIReasoning(analysis)
    };
    for (const conflict of conflicts) {
      const recommendation = this.getAIRecommendation(conflict, analysis);
      conflict.resolution = {
        strategy,
        resolvedBy: "ai_system",
        resolvedAt: Date.now(),
        notes: recommendation
      };
    }
    return {
      strategy,
      resolvedBy: "ai_system",
      resolvedAt: Date.now(),
      notes: `AI analysis with ${strategy.confidence * 100}% confidence`
    };
  }
  /**
   * Strategy: Hybrid
   * Combines multiple strategies based on conflict type
   */
  async hybridStrategy(conflicts, stack1, stack2, context) {
    logger.info("Applying hybrid strategy");
    const strategy = {
      type: "hybrid",
      confidence: 0.9,
      reasoning: "Using optimal strategy for each conflict type"
    };
    for (const conflict of conflicts) {
      let subStrategy;
      switch (conflict.type) {
        case "parallel_solution":
          subStrategy = "keep_both";
          break;
        case "conflicting_decision":
          subStrategy = "ai_suggest";
          break;
        case "structural_divergence":
          subStrategy = context.userRole === "senior" || context.userRole === "lead" ? "senior_override" : "team_vote";
          break;
        default:
          subStrategy = "ai_suggest";
      }
      conflict.resolution = {
        strategy: {
          ...strategy,
          reasoning: `${subStrategy} for ${conflict.type}`
        },
        resolvedBy: context.userId,
        resolvedAt: Date.now(),
        notes: `Hybrid resolution using ${subStrategy}`
      };
    }
    return {
      strategy,
      resolvedBy: context.userId,
      resolvedAt: Date.now(),
      notes: `Hybrid strategy optimized for each conflict type`
    };
  }
  /**
   * Execute the merge based on resolution
   */
  async executeMerge(stack1, stack2, conflicts, resolution) {
    const mergedFrameId = uuidv4();
    const rollbackPoint = this.createRollbackPoint(stack1, stack2);
    const notifications = [];
    try {
      const mergedFrames = this.mergeFrames(
        stack1,
        stack2,
        conflicts,
        resolution
      );
      const isValid = this.validateMerge(mergedFrames, conflicts);
      if (!isValid) {
        throw new Error("Merge validation failed");
      }
      const notifyResults = await this.sendNotifications(conflicts, resolution);
      notifications.push(...notifyResults);
      logger.info("Merge executed successfully", {
        mergedFrameId,
        frameCount: mergedFrames.length,
        strategy: resolution.strategy.type
      });
      return {
        success: true,
        mergedFrameId,
        conflicts,
        resolution,
        rollbackPoint,
        notifications
      };
    } catch (error) {
      logger.error("Merge execution failed", error);
      return {
        success: false,
        conflicts,
        resolution,
        rollbackPoint,
        notifications
      };
    }
  }
  /**
   * Count votes from team members
   */
  countVotes(votes) {
    const counts = {
      frame1: 0,
      frame2: 0,
      both: 0,
      neither: 0,
      total: votes.length,
      consensus: 0
    };
    for (const vote of votes) {
      counts[vote.choice]++;
    }
    const maxVotes = Math.max(
      counts.frame1,
      counts.frame2,
      counts.both,
      counts.neither
    );
    counts.consensus = Math.round(maxVotes / counts.total * 100);
    return counts;
  }
  /**
   * Calculate confidence based on vote distribution
   */
  calculateVoteConfidence(voteResults) {
    if (voteResults.consensus >= 80) return 0.95;
    if (voteResults.consensus >= 60) return 0.75;
    if (voteResults.consensus >= 40) return 0.5;
    return 0.3;
  }
  /**
   * Determine winner from vote results
   */
  determineVoteWinner(conflict, voteResults) {
    if (voteResults.frame1 > voteResults.frame2) return conflict.frameId1;
    if (voteResults.frame2 > voteResults.frame1) return conflict.frameId2;
    if (voteResults.both > voteResults.neither) return "both";
    return "neither";
  }
  /**
   * Determine preferred stack for senior override
   */
  determinePreferredStack(stack1, stack2, context) {
    if (stack1.owner === context.userId) return stack1;
    if (stack2.owner === context.userId) return stack2;
    if (stack1.lastModified > stack2.lastModified) return stack1;
    if (stack2.frames.filter((f) => f.state === "closed").length > stack1.frames.filter((f) => f.state === "closed").length) {
      return stack2;
    }
    return stack1;
  }
  /**
   * Analyze frame quality for AI suggestions
   */
  async analyzeFrameQuality(stack1, stack2) {
    const analysis = {
      stack1: {
        completeness: this.calculateCompleteness(stack1),
        efficiency: this.calculateEfficiency(stack1),
        quality: this.calculateQuality(stack1)
      },
      stack2: {
        completeness: this.calculateCompleteness(stack2),
        efficiency: this.calculateEfficiency(stack2),
        quality: this.calculateQuality(stack2)
      }
    };
    return analysis;
  }
  /**
   * Calculate stack completeness
   */
  calculateCompleteness(stack) {
    const closedFrames = stack.frames.filter(
      (f) => f.state === "closed"
    ).length;
    return closedFrames / stack.frames.length;
  }
  /**
   * Calculate stack efficiency
   */
  calculateEfficiency(stack) {
    let totalDuration = 0;
    let completedFrames = 0;
    for (const frame of stack.frames) {
      if (frame.closed_at && frame.created_at) {
        totalDuration += frame.closed_at - frame.created_at;
        completedFrames++;
      }
    }
    if (completedFrames === 0) return 0;
    const avgDuration = totalDuration / completedFrames;
    return Math.max(0, Math.min(1, 3e5 / avgDuration));
  }
  /**
   * Calculate stack quality
   */
  calculateQuality(stack) {
    let qualityScore = 0;
    for (const frame of stack.frames) {
      if (frame.outputs && Object.keys(frame.outputs).length > 0)
        qualityScore += 0.3;
      if (frame.digest_text) qualityScore += 0.3;
      if (frame.state === "closed") qualityScore += 0.4;
    }
    return Math.min(1, qualityScore / stack.frames.length);
  }
  /**
   * Generate AI reasoning for resolution
   */
  generateAIReasoning(analysis) {
    const stack1Score = analysis.stack1.completeness * 0.3 + analysis.stack1.efficiency * 0.3 + analysis.stack1.quality * 0.4;
    const stack2Score = analysis.stack2.completeness * 0.3 + analysis.stack2.efficiency * 0.3 + analysis.stack2.quality * 0.4;
    if (stack1Score > stack2Score) {
      return `Stack 1 shows higher overall quality (${(stack1Score * 100).toFixed(1)}% vs ${(stack2Score * 100).toFixed(1)}%)`;
    } else {
      return `Stack 2 shows higher overall quality (${(stack2Score * 100).toFixed(1)}% vs ${(stack1Score * 100).toFixed(1)}%)`;
    }
  }
  /**
   * Get AI recommendation for specific conflict
   */
  getAIRecommendation(conflict) {
    switch (conflict.type) {
      case "parallel_solution":
        return "Recommend keeping both solutions for A/B testing";
      case "conflicting_decision":
        return "Recommend the decision with higher quality score";
      case "structural_divergence":
        return "Recommend restructuring to accommodate both approaches";
      default:
        return "Recommend manual review for this conflict";
    }
  }
  /**
   * Create rollback point before merge
   */
  createRollbackPoint(_stack1, _stack2) {
    const rollbackId = uuidv4();
    logger.info("Created rollback point", { rollbackId });
    return rollbackId;
  }
  /**
   * Merge frames based on resolution
   */
  mergeFrames(stack1, stack2, conflicts, resolution) {
    const mergedFrames = [];
    const processedIds = /* @__PURE__ */ new Set();
    switch (resolution.strategy.type) {
      case "keep_both":
        mergedFrames.push(...stack1.frames, ...stack2.frames);
        break;
      case "team_vote":
      case "senior_override":
      case "ai_suggest":
        for (const frame of stack1.frames) {
          const conflict = conflicts.find((c) => c.frameId1 === frame.frame_id);
          if (!conflict || conflict.resolution?.strategy.type === "keep_both") {
            mergedFrames.push(frame);
            processedIds.add(frame.frame_id);
          }
        }
        for (const frame of stack2.frames) {
          if (!processedIds.has(frame.frame_id)) {
            const conflict = conflicts.find(
              (c) => c.frameId2 === frame.frame_id
            );
            if (!conflict || conflict.resolution?.strategy.type === "keep_both") {
              mergedFrames.push(frame);
            }
          }
        }
        break;
      case "hybrid":
        this.hybridMerge(stack1, stack2, conflicts, mergedFrames);
        break;
    }
    return mergedFrames;
  }
  /**
   * Hybrid merge implementation
   */
  hybridMerge(stack1, stack2, conflicts, mergedFrames) {
    const conflictMap = /* @__PURE__ */ new Map();
    for (const conflict of conflicts) {
      conflictMap.set(conflict.frameId1, conflict);
      conflictMap.set(conflict.frameId2, conflict);
    }
    for (const frame of [...stack1.frames, ...stack2.frames]) {
      const conflict = conflictMap.get(frame.frame_id);
      if (!conflict) {
        if (!mergedFrames.find((f) => f.frame_id === frame.frame_id)) {
          mergedFrames.push(frame);
        }
      } else if (conflict.type === "parallel_solution") {
        if (!mergedFrames.find((f) => f.frame_id === frame.frame_id)) {
          mergedFrames.push(frame);
        }
      }
    }
  }
  /**
   * Validate merge integrity
   */
  validateMerge(mergedFrames, conflicts) {
    const ids = /* @__PURE__ */ new Set();
    for (const frame of mergedFrames) {
      if (ids.has(frame.frame_id)) {
        logger.error("Duplicate frame ID in merge", {
          frameId: frame.frame_id
        });
        return false;
      }
      ids.add(frame.frame_id);
    }
    for (const frame of mergedFrames) {
      if (frame.parent_frame_id) {
        const parent = mergedFrames.find(
          (f) => f.frame_id === frame.parent_frame_id
        );
        if (!parent) {
          logger.warn("Orphaned frame in merge", { frameId: frame.frame_id });
        }
      }
    }
    for (const conflict of conflicts) {
      if (!conflict.resolution) {
        logger.error("Unresolved conflict in merge", {
          conflictId: conflict.id
        });
        return false;
      }
    }
    return true;
  }
  /**
   * Send notifications about merge
   */
  async sendNotifications(conflicts, resolution) {
    const notifications = [];
    const notification = {
      userId: resolution.resolvedBy || "team",
      type: "in-app",
      sent: true,
      timestamp: Date.now()
    };
    notifications.push(notification);
    logger.info("Notifications sent", { count: notifications.length });
    return notifications;
  }
  /**
   * Store resolution in history
   */
  storeResolution(mergeId, resolution) {
    this.resolutionHistory.set(mergeId, resolution);
    logger.info("Resolution stored in history", {
      mergeId,
      strategy: resolution.strategy.type
    });
  }
  /**
   * Get resolution history for analysis
   */
  getResolutionHistory() {
    return this.resolutionHistory;
  }
}
export {
  ResolutionEngine
};
//# sourceMappingURL=resolution-engine.js.map
