import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import * as fs from "fs/promises";
import * as path from "path";
import { execSync } from "child_process";
import { logger } from "../../../core/monitoring/logger.js";
class StateReconciler {
  config;
  ralphDir = ".ralph";
  reconciliationLog = [];
  constructor(config) {
    this.config = {
      precedence: config?.precedence || ["git", "files", "memory"],
      conflictResolution: config?.conflictResolution || "automatic",
      syncInterval: config?.syncInterval || 5e3,
      validateConsistency: config?.validateConsistency ?? true
    };
  }
  /**
   * Reconcile state from multiple sources
   */
  async reconcile(sources) {
    logger.info("Reconciling state from sources", {
      sources: sources.map((s) => ({ type: s.type, confidence: s.confidence }))
    });
    const sortedSources = this.sortByPrecedence(sources);
    const conflicts = this.detectConflicts(sortedSources);
    if (conflicts.length > 0) {
      logger.warn("State conflicts detected", {
        count: conflicts.length,
        fields: conflicts.map((c) => c.field)
      });
      const resolutions = await this.resolveConflicts(conflicts);
      return this.applyResolutions(sortedSources[0].state, resolutions);
    }
    return this.mergeStates(sortedSources);
  }
  /**
   * Detect conflicts between state sources
   */
  detectConflicts(sources) {
    const conflicts = [];
    const fields = /* @__PURE__ */ new Set();
    sources.forEach((source) => {
      Object.keys(source.state).forEach((field) => fields.add(field));
    });
    for (const field of fields) {
      const values = sources.filter((s) => s.state[field] !== void 0).map((s) => ({
        source: s,
        value: s.state[field]
      }));
      if (values.length > 1 && !this.valuesMatch(values.map((v) => v.value))) {
        conflicts.push({
          field,
          sources: values.map((v) => v.source),
          severity: this.assessConflictSeverity(field),
          suggestedResolution: this.suggestResolution(field, values.map((v) => v.source))
        });
      }
    }
    return conflicts;
  }
  /**
   * Resolve a single conflict
   */
  async resolveConflict(conflict) {
    const resolution = await this.resolveConflictByStrategy(conflict);
    this.reconciliationLog.push(resolution);
    logger.debug("Conflict resolved", {
      field: conflict.field,
      resolution: resolution.source,
      rationale: resolution.rationale
    });
    return resolution;
  }
  /**
   * Validate state consistency
   */
  async validateConsistency(state) {
    const errors = [];
    const warnings = [];
    try {
      await this.validateFileSystemState(state, errors, warnings);
      this.validateGitState(state, errors, warnings);
      this.validateLogicalConsistency(state, errors, warnings);
      return {
        testsPass: errors.length === 0,
        lintClean: true,
        buildSuccess: true,
        errors,
        warnings
      };
    } catch (error) {
      errors.push(`Validation failed: ${error.message}`);
      return {
        testsPass: false,
        lintClean: false,
        buildSuccess: false,
        errors,
        warnings
      };
    }
  }
  /**
   * Get state from git
   */
  async getGitState() {
    try {
      const currentCommit = execSync("git rev-parse HEAD", { encoding: "utf8" }).trim();
      const branch = execSync("git branch --show-current", { encoding: "utf8" }).trim();
      const uncommittedChanges = execSync("git status --porcelain", { encoding: "utf8" });
      const ralphCommits = execSync('git log --oneline --grep="Ralph iteration"', {
        encoding: "utf8"
      }).split("\n").filter(Boolean);
      const lastRalphCommit = ralphCommits[0]?.split(" ")[0];
      const iteration = ralphCommits.length;
      return {
        type: "git",
        state: {
          currentCommit,
          startCommit: lastRalphCommit,
          iteration,
          status: uncommittedChanges ? "running" : "completed"
        },
        timestamp: Date.now(),
        confidence: 0.9
      };
    } catch (error) {
      logger.error("Failed to get git state", { error: error.message });
      return {
        type: "git",
        state: {},
        timestamp: Date.now(),
        confidence: 0.1
      };
    }
  }
  /**
   * Get state from file system
   */
  async getFileState() {
    try {
      const statePath = path.join(this.ralphDir, "state.json");
      const iterationPath = path.join(this.ralphDir, "iteration.txt");
      const feedbackPath = path.join(this.ralphDir, "feedback.txt");
      const taskPath = path.join(this.ralphDir, "task.md");
      const criteriaPath = path.join(this.ralphDir, "completion-criteria.md");
      const [stateData, iteration, feedback, task, criteria] = await Promise.all([
        fs.readFile(statePath, "utf8").catch(() => "{}"),
        fs.readFile(iterationPath, "utf8").catch(() => "0"),
        fs.readFile(feedbackPath, "utf8").catch(() => ""),
        fs.readFile(taskPath, "utf8").catch(() => ""),
        fs.readFile(criteriaPath, "utf8").catch(() => "")
      ]);
      const state = JSON.parse(stateData);
      return {
        type: "files",
        state: {
          ...state,
          iteration: parseInt(iteration.trim()),
          feedback: feedback.trim() || void 0,
          task: task.trim(),
          criteria: criteria.trim()
        },
        timestamp: Date.now(),
        confidence: 0.95
      };
    } catch (error) {
      logger.error("Failed to get file state", { error: error.message });
      return {
        type: "files",
        state: {},
        timestamp: Date.now(),
        confidence: 0.1
      };
    }
  }
  /**
   * Get state from memory (StackMemory)
   */
  async getMemoryState(loopId) {
    try {
      return {
        type: "memory",
        state: {
          loopId,
          lastUpdateTime: Date.now()
        },
        timestamp: Date.now(),
        confidence: 0.8
      };
    } catch (error) {
      logger.error("Failed to get memory state", { error: error.message });
      return {
        type: "memory",
        state: {},
        timestamp: Date.now(),
        confidence: 0.1
      };
    }
  }
  /**
   * Sort sources by configured precedence
   */
  sortByPrecedence(sources) {
    return sources.sort((a, b) => {
      const aIndex = this.config.precedence.indexOf(a.type);
      const bIndex = this.config.precedence.indexOf(b.type);
      if (aIndex === -1 && bIndex === -1) {
        return b.confidence - a.confidence;
      }
      if (aIndex === -1) return 1;
      if (bIndex === -1) return -1;
      return aIndex - bIndex;
    });
  }
  /**
   * Check if values match
   */
  valuesMatch(values) {
    if (values.length === 0) return true;
    const first = JSON.stringify(values[0]);
    return values.every((v) => JSON.stringify(v) === first);
  }
  /**
   * Assess conflict severity
   */
  assessConflictSeverity(field) {
    const highSeverityFields = ["loopId", "task", "criteria", "status"];
    const mediumSeverityFields = ["iteration", "currentCommit", "feedback"];
    if (highSeverityFields.includes(field)) return "high";
    if (mediumSeverityFields.includes(field)) return "medium";
    return "low";
  }
  /**
   * Suggest resolution based on field and sources
   */
  suggestResolution(field, sources) {
    const sorted = this.sortByPrecedence(sources);
    const highestConfidence = sorted.reduce(
      (max, s) => s.confidence > max.confidence ? s : max
    );
    return highestConfidence.state[field];
  }
  /**
   * Resolve conflicts based on configured strategy
   */
  async resolveConflicts(conflicts) {
    const resolutions = [];
    for (const conflict of conflicts) {
      const resolution = await this.resolveConflictByStrategy(conflict);
      resolutions.push(resolution);
    }
    return resolutions;
  }
  /**
   * Resolve conflict based on strategy
   */
  async resolveConflictByStrategy(conflict) {
    switch (this.config.conflictResolution) {
      case "automatic":
        return this.automaticResolution(conflict);
      case "manual":
        return this.manualResolution(conflict);
      case "interactive":
        return this.interactiveResolution(conflict);
      default:
        return this.automaticResolution(conflict);
    }
  }
  /**
   * Automatic resolution based on precedence and confidence
   */
  automaticResolution(conflict) {
    const sorted = this.sortByPrecedence(conflict.sources);
    const winner = sorted[0];
    return {
      field: conflict.field,
      value: winner.state[conflict.field],
      source: winner.type,
      rationale: `Automatic resolution: ${winner.type} has highest precedence (confidence: ${winner.confidence})`
    };
  }
  /**
   * Manual resolution (uses suggested resolution)
   */
  manualResolution(conflict) {
    return {
      field: conflict.field,
      value: conflict.suggestedResolution,
      source: "manual",
      rationale: "Manual resolution: using suggested value"
    };
  }
  /**
   * Interactive resolution (would prompt user in real implementation)
   */
  async interactiveResolution(conflict) {
    logger.info("Interactive resolution required", {
      field: conflict.field,
      options: conflict.sources.map((s) => ({
        type: s.type,
        value: s.state[conflict.field],
        confidence: s.confidence
      }))
    });
    return this.automaticResolution(conflict);
  }
  /**
   * Apply resolutions to base state
   */
  applyResolutions(baseState, resolutions) {
    const resolvedState = { ...baseState };
    for (const resolution of resolutions) {
      resolvedState[resolution.field] = resolution.value;
    }
    return resolvedState;
  }
  /**
   * Merge states without conflicts
   */
  mergeStates(sources) {
    const merged = {};
    for (const source of sources) {
      Object.assign(merged, source.state);
    }
    return merged;
  }
  /**
   * Validate file system state
   */
  async validateFileSystemState(state, errors, warnings) {
    try {
      const ralphDirExists = await fs.stat(this.ralphDir).then(() => true).catch(() => false);
      if (!ralphDirExists) {
        warnings.push("Ralph directory does not exist");
        return;
      }
      const requiredFiles = ["task.md", "state.json", "iteration.txt"];
      for (const file of requiredFiles) {
        const filePath = path.join(this.ralphDir, file);
        const exists = await fs.stat(filePath).then(() => true).catch(() => false);
        if (!exists) {
          warnings.push(`Missing file: ${file}`);
        }
      }
    } catch (error) {
      errors.push(`File system validation failed: ${error.message}`);
    }
  }
  /**
   * Validate git state
   */
  validateGitState(state, errors, warnings) {
    try {
      const isGitRepo = execSync("git rev-parse --is-inside-work-tree", {
        encoding: "utf8"
      }).trim() === "true";
      if (!isGitRepo) {
        warnings.push("Not in a git repository");
      }
      if (state.currentCommit && state.startCommit) {
        try {
          execSync(`git rev-parse ${state.currentCommit}`, { encoding: "utf8" });
        } catch {
          errors.push(`Invalid current commit: ${state.currentCommit}`);
        }
        try {
          execSync(`git rev-parse ${state.startCommit}`, { encoding: "utf8" });
        } catch {
          warnings.push(`Invalid start commit: ${state.startCommit}`);
        }
      }
    } catch (error) {
      warnings.push(`Git validation failed: ${error.message}`);
    }
  }
  /**
   * Validate logical consistency
   */
  validateLogicalConsistency(state, errors, warnings) {
    if (state.iteration < 0) {
      errors.push("Invalid iteration number: cannot be negative");
    }
    if (state.status === "completed" && !state.completionData) {
      warnings.push("Status is completed but no completion data");
    }
    if (state.lastUpdateTime && state.startTime && state.lastUpdateTime < state.startTime) {
      errors.push("Last update time is before start time");
    }
    if (!state.task) {
      errors.push("No task defined");
    }
    if (!state.criteria) {
      warnings.push("No completion criteria defined");
    }
  }
}
export {
  StateReconciler
};
//# sourceMappingURL=state-reconciler.js.map
