import { EventEmitter } from "events";
import { execSync } from "child_process";
import * as fs from "fs/promises";
import * as path from "path";
class PostTaskHooks extends EventEmitter {
  config;
  frameManager;
  dbManager;
  isActive = false;
  lastProcessedFrame;
  constructor(frameManager, dbManager, config) {
    super();
    this.frameManager = frameManager;
    this.dbManager = dbManager;
    this.config = {
      projectRoot: process.cwd(),
      qualityGates: {
        runTests: true,
        requireTestCoverage: false,
        runCodeReview: true,
        runLinter: true,
        blockOnFailure: false
      },
      testFrameworks: {
        detected: []
      },
      reviewConfig: {
        reviewOnEveryChange: false,
        reviewOnTaskComplete: true,
        focusAreas: [
          "security",
          "performance",
          "maintainability",
          "correctness"
        ],
        skipPatterns: ["*.test.ts", "*.spec.js", "dist/", "node_modules/"]
      },
      ...config
    };
  }
  /**
   * Initialize post-task hooks
   */
  async initialize() {
    if (this.isActive) return;
    await this.detectTestFrameworks();
    this.setupFrameListeners();
    await this.setupFileWatchers();
    this.isActive = true;
    console.log("\u2705 Post-task hooks initialized");
    this.emit("initialized", this.config);
  }
  /**
   * Detect available test frameworks and commands
   */
  async detectTestFrameworks() {
    const packageJsonPath = path.join(this.config.projectRoot, "package.json");
    try {
      const packageJson = JSON.parse(
        await fs.readFile(packageJsonPath, "utf-8")
      );
      const scripts = packageJson.scripts || {};
      const dependencies = {
        ...packageJson.dependencies,
        ...packageJson.devDependencies
      };
      const frameworks = [];
      if (dependencies.jest) frameworks.push("jest");
      if (dependencies.vitest) frameworks.push("vitest");
      if (dependencies.mocha) frameworks.push("mocha");
      if (dependencies.playwright) frameworks.push("playwright");
      if (dependencies.cypress) frameworks.push("cypress");
      this.config.testFrameworks.detected = frameworks;
      if (scripts.test) {
        this.config.testFrameworks.testCommand = "npm test";
      } else if (scripts["test:run"]) {
        this.config.testFrameworks.testCommand = "npm run test:run";
      }
      if (scripts.coverage) {
        this.config.testFrameworks.coverageCommand = "npm run coverage";
      }
      if (scripts.lint) {
        this.config.testFrameworks.lintCommand = "npm run lint";
      }
    } catch (error) {
      console.warn("Could not detect test frameworks:", error);
    }
  }
  /**
   * Set up frame event listeners
   */
  setupFrameListeners() {
    this.frameManager.on(
      "frame:closed",
      async (frameId, frameData) => {
        if (frameData.type === "task" || frameData.type === "subtask") {
          await this.handleTaskCompletion({
            taskType: "task_complete",
            frameId,
            frameName: frameData.name || "Unnamed task",
            files: this.extractFilesFromFrame(frameData),
            changes: this.calculateChanges(frameData),
            metadata: frameData.metadata || {}
          });
        }
      }
    );
    this.frameManager.on(
      "frame:event",
      async (frameId, eventType, data) => {
        if (eventType === "code_change" || eventType === "file_modified") {
          await this.handleTaskCompletion({
            taskType: "code_change",
            frameId,
            frameName: data.description || "Code change",
            files: data.files || [],
            changes: data.changes || { added: 0, removed: 0, modified: 1 },
            metadata: data
          });
        }
      }
    );
  }
  /**
   * Set up file watchers for real-time code change detection
   */
  async setupFileWatchers() {
    try {
      const chokidar = await import("chokidar");
      const watcher = chokidar.watch(
        [
          "**/*.{ts,js,tsx,jsx,py,go,rs,java,cpp,c}",
          "!node_modules/**",
          "!dist/**",
          "!build/**"
        ],
        {
          cwd: this.config.projectRoot,
          ignored: /node_modules/,
          persistent: true
        }
      );
      let changeQueue = [];
      let debounceTimer = null;
      watcher.on("change", (filePath) => {
        changeQueue.push(filePath);
        if (debounceTimer) clearTimeout(debounceTimer);
        debounceTimer = setTimeout(async () => {
          if (changeQueue.length > 0) {
            await this.handleFileChanges([...changeQueue]);
            changeQueue = [];
          }
        }, 2e3);
      });
    } catch (error) {
      console.warn("File watching not available:", error);
    }
  }
  /**
   * Handle task completion events
   */
  async handleTaskCompletion(event) {
    if (this.lastProcessedFrame === event.frameId && event.taskType !== "code_change") {
      return;
    }
    this.lastProcessedFrame = event.frameId;
    console.log(
      `\u{1F50D} Task completed: ${event.frameName} (${event.files.length} files changed)`
    );
    this.emit("task:completed", event);
    const results = await this.runQualityGates(event);
    const allPassed = results.every((r) => r.passed);
    if (allPassed) {
      console.log("\u2705 All quality gates passed");
      this.emit("quality:passed", { event, results });
    } else {
      console.log("\u26A0\uFE0F Quality gate failures detected");
      this.emit("quality:failed", { event, results });
      if (this.config.qualityGates.blockOnFailure) {
        await this.blockFurtherWork(results);
      }
    }
    await this.recordQualityResults(event.frameId, results);
  }
  /**
   * Handle file changes
   */
  async handleFileChanges(files) {
    if (!this.config.reviewConfig.reviewOnEveryChange) return;
    const filteredFiles = files.filter((file) => {
      return !this.config.reviewConfig.skipPatterns.some((pattern) => {
        return file.includes(pattern.replace("*", ""));
      });
    });
    if (filteredFiles.length === 0) return;
    await this.handleTaskCompletion({
      taskType: "file_modified",
      frameId: "file-watcher",
      frameName: "File changes detected",
      files: filteredFiles,
      changes: { added: 0, removed: 0, modified: filteredFiles.length },
      metadata: { trigger: "file_watcher" }
    });
  }
  /**
   * Run all configured quality gates
   */
  async runQualityGates(event) {
    const results = [];
    if (this.config.qualityGates.runLinter) {
      results.push(await this.runLinter(event.files));
    }
    if (this.config.qualityGates.runTests) {
      results.push(await this.runTests(event.files));
    }
    if (this.config.qualityGates.requireTestCoverage) {
      results.push(await this.checkTestCoverage(event.files));
    }
    if (this.config.qualityGates.runCodeReview) {
      results.push(await this.runCodeReview(event));
    }
    return results;
  }
  /**
   * Run linter on changed files
   */
  async runLinter(files) {
    const start = Date.now();
    try {
      if (!this.config.testFrameworks.lintCommand) {
        return {
          gate: "linter",
          passed: true,
          output: "No lint command configured",
          duration: Date.now() - start
        };
      }
      const output = execSync(this.config.testFrameworks.lintCommand, {
        cwd: this.config.projectRoot,
        encoding: "utf-8",
        timeout: 3e4
        // 30 second timeout
      });
      return {
        gate: "linter",
        passed: true,
        output,
        duration: Date.now() - start
      };
    } catch (error) {
      return {
        gate: "linter",
        passed: false,
        output: error.stdout || error.message,
        duration: Date.now() - start,
        issues: this.parseLintErrors(error.stdout || error.message)
      };
    }
  }
  /**
   * Run tests
   */
  async runTests(files) {
    const start = Date.now();
    try {
      if (!this.config.testFrameworks.testCommand) {
        return {
          gate: "tests",
          passed: true,
          output: "No test command configured",
          duration: Date.now() - start
        };
      }
      const output = execSync(this.config.testFrameworks.testCommand, {
        cwd: this.config.projectRoot,
        encoding: "utf-8",
        timeout: 12e4
        // 2 minute timeout
      });
      return {
        gate: "tests",
        passed: true,
        output,
        duration: Date.now() - start
      };
    } catch (error) {
      return {
        gate: "tests",
        passed: false,
        output: error.stdout || error.message,
        duration: Date.now() - start,
        issues: this.parseTestFailures(error.stdout || error.message)
      };
    }
  }
  /**
   * Check test coverage
   */
  async checkTestCoverage(files) {
    const start = Date.now();
    try {
      if (!this.config.testFrameworks.coverageCommand) {
        return {
          gate: "coverage",
          passed: true,
          output: "No coverage command configured",
          duration: Date.now() - start
        };
      }
      const output = execSync(this.config.testFrameworks.coverageCommand, {
        cwd: this.config.projectRoot,
        encoding: "utf-8",
        timeout: 12e4
      });
      const coverageMatch = output.match(/(\d+\.?\d*)%/);
      const coverage = coverageMatch ? parseFloat(coverageMatch[1]) : 0;
      const threshold = 80;
      return {
        gate: "coverage",
        passed: coverage >= threshold,
        output,
        duration: Date.now() - start,
        issues: coverage < threshold ? [
          {
            type: "coverage_low",
            file: "overall",
            message: `Coverage ${coverage}% is below threshold ${threshold}%`,
            severity: "warning"
          }
        ] : void 0
      };
    } catch (error) {
      return {
        gate: "coverage",
        passed: false,
        output: error.stdout || error.message,
        duration: Date.now() - start,
        issues: [
          {
            type: "coverage_low",
            file: "overall",
            message: "Coverage check failed",
            severity: "error"
          }
        ]
      };
    }
  }
  /**
   * Run code review using AI agent
   */
  async runCodeReview(event) {
    const start = Date.now();
    try {
      const reviewPrompt = this.generateCodeReviewPrompt(event);
      const review = await this.callCodeReviewAgent(reviewPrompt, event.files);
      return {
        gate: "code_review",
        passed: !review.issues || review.issues.length === 0,
        output: review.summary,
        duration: Date.now() - start,
        issues: review.issues
      };
    } catch (error) {
      return {
        gate: "code_review",
        passed: false,
        output: `Code review failed: ${error.message}`,
        duration: Date.now() - start
      };
    }
  }
  /**
   * Generate code review prompt
   */
  generateCodeReviewPrompt(event) {
    return `
Please review the following code changes:

Task: ${event.frameName}
Files changed: ${event.files.join(", ")}
Changes: +${event.changes.added}, -${event.changes.removed}, ~${event.changes.modified}

Focus areas: ${this.config.reviewConfig.focusAreas.join(", ")}

Please check for:
1. Security vulnerabilities
2. Performance issues  
3. Code maintainability
4. Correctness and logic errors
5. Best practices adherence

Provide specific, actionable feedback.
`;
  }
  /**
   * Call code review agent (placeholder for actual implementation)
   */
  async callCodeReviewAgent(prompt, files) {
    return {
      summary: `Reviewed ${files.length} files. Code quality looks good.`,
      issues: []
    };
  }
  /**
   * Parse lint errors into structured issues
   */
  parseLintErrors(output) {
    const issues = [];
    const lines = output.split("\n");
    for (const line of lines) {
      const match = line.match(
        /^(.+?):(\d+):(\d+):\s*(error|warning):\s*(.+)$/
      );
      if (match) {
        issues.push({
          type: "lint_error",
          file: match[1],
          line: parseInt(match[2]),
          message: match[5],
          severity: match[4]
        });
      }
    }
    return issues;
  }
  /**
   * Parse test failures into structured issues
   */
  parseTestFailures(output) {
    const issues = [];
    const lines = output.split("\n");
    for (const line of lines) {
      if (line.includes("FAIL") || line.includes("\u2717")) {
        issues.push({
          type: "test_failure",
          file: "unknown",
          message: line.trim(),
          severity: "error"
        });
      }
    }
    return issues;
  }
  /**
   * Block further work when quality gates fail
   */
  async blockFurtherWork(results) {
    const failedGates = results.filter((r) => !r.passed);
    console.log("\u{1F6AB} Quality gates failed - blocking further work:");
    failedGates.forEach((gate) => {
      console.log(`   ${gate.gate}: ${gate.output}`);
      if (gate.issues) {
        gate.issues.forEach((issue) => {
          console.log(
            `     - ${issue.severity}: ${issue.message} (${issue.file}:${issue.line || 0})`
          );
        });
      }
    });
    console.log("\n\u{1F527} Fix these issues before continuing:");
    const allIssues = failedGates.flatMap((g) => g.issues || []);
    allIssues.forEach((issue, i) => {
      console.log(`${i + 1}. ${issue.message}`);
    });
  }
  /**
   * Record quality results in frame metadata
   */
  async recordQualityResults(frameId, results) {
    try {
      const frame = await this.frameManager.getFrame(frameId);
      if (frame) {
        frame.metadata = {
          ...frame.metadata,
          qualityGates: {
            timestamp: (/* @__PURE__ */ new Date()).toISOString(),
            results,
            passed: results.every((r) => r.passed),
            totalDuration: results.reduce((sum, r) => sum + r.duration, 0)
          }
        };
        await this.frameManager.updateFrame(frameId, frame);
      }
    } catch (error) {
      console.error("Failed to record quality results:", error);
    }
  }
  /**
   * Extract files from frame data
   */
  extractFilesFromFrame(frameData) {
    const files = [];
    if (frameData.metadata?.files) {
      files.push(...frameData.metadata.files);
    }
    if (frameData.events) {
      frameData.events.forEach((event) => {
        if (event.type === "file_change" && event.data?.file) {
          files.push(event.data.file);
        }
      });
    }
    return [...new Set(files)];
  }
  /**
   * Calculate changes from frame data
   */
  calculateChanges(frameData) {
    return {
      added: frameData.metadata?.linesAdded || 0,
      removed: frameData.metadata?.linesRemoved || 0,
      modified: frameData.metadata?.filesModified || 1
    };
  }
  /**
   * Stop post-task hooks
   */
  async stop() {
    this.isActive = false;
    this.removeAllListeners();
    console.log("\u{1F6D1} Post-task hooks stopped");
  }
  /**
   * Get current configuration
   */
  getConfig() {
    return { ...this.config };
  }
  /**
   * Update configuration
   */
  updateConfig(updates) {
    this.config = { ...this.config, ...updates };
    this.emit("config:updated", this.config);
  }
}
export {
  PostTaskHooks
};
//# sourceMappingURL=post-task-hooks.js.map
