import { fileURLToPath as __fileURLToPath } from 'url';
import { dirname as __pathDirname } from 'path';
const __filename = __fileURLToPath(import.meta.url);
const __dirname = __pathDirname(__filename);
import * as ts from "typescript";
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
import { dirname, join, basename } from "path";
import { execSync } from "child_process";
import { glob } from "glob";
import { logger } from "../core/monitoring/logger.js";
class TestingAgent {
  projectRoot;
  testDir;
  mockDir;
  fixtureDir;
  constructor(projectRoot = process.cwd()) {
    this.projectRoot = projectRoot;
    this.testDir = join(projectRoot, "src", "__tests__");
    this.mockDir = join(projectRoot, "src", "__mocks__");
    this.fixtureDir = join(projectRoot, "src", "__fixtures__");
  }
  /**
   * Analyze code coverage from existing reports
   */
  async analyzeCodeCoverage(targetPath) {
    const coveragePath = join(
      this.projectRoot,
      "coverage",
      "coverage-final.json"
    );
    if (!existsSync(coveragePath)) {
      try {
        execSync("npm run test -- --coverage --silent", {
          cwd: this.projectRoot,
          stdio: "pipe"
        });
      } catch (error) {
        logger.warn("Coverage generation failed", { error });
      }
    }
    if (existsSync(coveragePath)) {
      const coverage = JSON.parse(
        readFileSync(coveragePath, "utf-8")
      );
      const fileCoverage = coverage[targetPath] || {};
      return {
        filePath: targetPath,
        lines: this.calculateCoverage(
          fileCoverage.s || {}
        ),
        branches: this.calculateCoverage(
          fileCoverage.b || {}
        ),
        functions: this.calculateCoverage(
          fileCoverage.f || {}
        ),
        uncoveredLines: this.findUncoveredLines(
          fileCoverage.statementMap || {},
          fileCoverage.s || {}
        )
      };
    }
    return {
      filePath: targetPath,
      lines: { total: 0, covered: 0, percentage: 0 },
      branches: { total: 0, covered: 0, percentage: 0 },
      functions: { total: 0, covered: 0, percentage: 0 },
      uncoveredLines: []
    };
  }
  /**
   * Generate unit tests for a function or module
   */
  async generateUnitTests(targetPath) {
    const sourceCode = readFileSync(targetPath, "utf-8");
    const sourceFile = ts.createSourceFile(
      targetPath,
      sourceCode,
      ts.ScriptTarget.Latest,
      true
    );
    const functions = this.extractFunctions(sourceFile);
    const classes = this.extractClasses(sourceFile);
    const tests = [];
    for (const func of functions) {
      tests.push(...this.generateFunctionTests(func));
    }
    for (const cls of classes) {
      tests.push(...this.generateClassTests(cls));
    }
    const testSuite = {
      filePath: this.getTestPath(targetPath),
      targetPath,
      describe: this.getModuleName(targetPath),
      imports: this.generateImports(targetPath, sourceFile),
      beforeEach: this.generateBeforeEach(classes),
      afterEach: this.generateAfterEach(classes),
      tests
    };
    return testSuite;
  }
  /**
   * Generate integration tests for a module
   */
  async generateIntegrationTests(modulePath) {
    const moduleFiles = glob.sync(join(modulePath, "**/*.ts"), {
      ignore: ["**/*.test.ts", "**/*.spec.ts", "**/node_modules/**"]
    });
    const tests = [];
    const dependencies = /* @__PURE__ */ new Set();
    for (const file of moduleFiles) {
      const sourceCode = readFileSync(file, "utf-8");
      const sourceFile = ts.createSourceFile(
        file,
        sourceCode,
        ts.ScriptTarget.Latest,
        true
      );
      this.findDependencies(sourceFile, dependencies);
    }
    tests.push(
      ...this.generateModuleIntegrationTests(
        modulePath,
        Array.from(dependencies)
      )
    );
    const testSuite = {
      filePath: this.getIntegrationTestPath(modulePath),
      targetPath: modulePath,
      describe: `${basename(modulePath)} Integration`,
      imports: this.generateIntegrationImports(modulePath, dependencies),
      beforeEach: this.generateIntegrationSetup(dependencies),
      afterEach: this.generateIntegrationCleanup(),
      tests
    };
    return testSuite;
  }
  /**
   * Generate edge case tests for a function
   */
  async generateEdgeCaseTests(targetPath, functionName) {
    const sourceCode = readFileSync(targetPath, "utf-8");
    const sourceFile = ts.createSourceFile(
      targetPath,
      sourceCode,
      ts.ScriptTarget.Latest,
      true
    );
    const func = this.findFunction(sourceFile, functionName);
    if (!func) {
      throw new Error(`Function ${functionName} not found in ${targetPath}`);
    }
    return this.generateFunctionEdgeCases(func);
  }
  /**
   * Execute tests and return results
   */
  async executeTests(pattern) {
    try {
      const output = execSync(`npm run test -- ${pattern} --reporter=json`, {
        cwd: this.projectRoot,
        encoding: "utf-8",
        stdio: "pipe"
      });
      const results = JSON.parse(output);
      return {
        passed: results.numPassedTests || 0,
        failed: results.numFailedTests || 0,
        skipped: results.numPendingTests || 0,
        duration: results.duration || 0,
        failures: this.extractFailures(results)
      };
    } catch (error) {
      return {
        passed: 0,
        failed: 1,
        skipped: 0,
        duration: 0,
        failures: [{ test: "Test execution", error: error.message }]
      };
    }
  }
  /**
   * Generate mock data for testing
   */
  generateMockData(schema) {
    const mockType = this.inferTypeFromSchema(schema);
    const mockValue = this.generateMockValue(mockType, schema);
    return {
      name: schema.name || "mockData",
      type: mockType,
      value: mockValue,
      implementation: this.generateMockImplementation(schema)
    };
  }
  /**
   * Create test fixtures
   */
  createTestFixtures(componentName) {
    const fixtures = [];
    fixtures.push({
      name: `${componentName}DefaultProps`,
      data: this.generateDefaultProps(),
      setup: this.generateFixtureSetup(componentName),
      teardown: this.generateFixtureTeardown(componentName)
    });
    fixtures.push({
      name: `${componentName}EdgeCaseProps`,
      data: this.generateEdgeCaseProps()
    });
    fixtures.push({
      name: `${componentName}TestData`,
      data: this.generateTestData()
    });
    return fixtures;
  }
  /**
   * Benchmark performance of a function
   */
  async benchmarkPerformance(targetPath, functionName) {
    const benchmarkCode = this.generateBenchmarkCode(targetPath, functionName);
    const benchmarkFile = join(
      this.testDir,
      "benchmarks",
      `${functionName}.bench.ts`
    );
    const benchDir = dirname(benchmarkFile);
    if (!existsSync(benchDir)) {
      mkdirSync(benchDir, { recursive: true });
    }
    writeFileSync(benchmarkFile, benchmarkCode);
    try {
      const output = execSync(
        `npx vitest bench ${benchmarkFile} --reporter=json`,
        {
          cwd: this.projectRoot,
          encoding: "utf-8",
          stdio: "pipe"
        }
      );
      const results = JSON.parse(output);
      return this.parseBenchmarkResults(results, functionName);
    } catch (error) {
      logger.error("Benchmark failed", { error });
      return {
        function: functionName,
        averageTime: 0,
        minTime: 0,
        maxTime: 0,
        iterations: 0,
        memoryUsage: 0
      };
    }
  }
  /**
   * Save generated test suite to file
   */
  async saveTestSuite(suite) {
    const testCode = this.generateTestCode(suite);
    const testDir = dirname(suite.filePath);
    if (!existsSync(testDir)) {
      mkdirSync(testDir, { recursive: true });
    }
    writeFileSync(suite.filePath, testCode);
    logger.info("Test suite saved", { path: suite.filePath });
  }
  // Private helper methods
  extractFunctions(sourceFile) {
    const functions = [];
    const visit = (node) => {
      if (ts.isFunctionDeclaration(node) && node.name) {
        functions.push(node);
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
    return functions;
  }
  extractClasses(sourceFile) {
    const classes = [];
    const visit = (node) => {
      if (ts.isClassDeclaration(node) && node.name) {
        classes.push(node);
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
    return classes;
  }
  generateFunctionTests(func) {
    const tests = [];
    const funcName = func.name?.getText() || "unknown";
    tests.push({
      name: `should execute ${funcName} successfully with valid input`,
      description: `Test normal execution of ${funcName}`,
      action: `const result = ${funcName}();`,
      assertion: "expect(result).toBeDefined();"
    });
    return tests;
  }
  generateClassTests(cls) {
    const tests = [];
    const className = cls.name?.getText() || "UnknownClass";
    tests.push({
      name: `should create instance of ${className}`,
      description: `Test ${className} instantiation`,
      action: `const instance = new ${className}()`,
      assertion: `expect(instance).toBeInstanceOf(${className})`
    });
    return tests;
  }
  generateFunctionEdgeCases(_func) {
    return [];
  }
  generateTestCode(suite) {
    const imports = suite.imports.join("\n");
    const tests = suite.tests.map((test) => this.formatTestCase(test)).join("\n\n  ");
    return `/**
 * Generated test suite for ${suite.targetPath}
 * Generated by TestingAgent
 */

${imports}

describe('${suite.describe}', () => {
${suite.beforeEach ? `  beforeEach(() => {
    ${suite.beforeEach}
  });
` : ""}
${suite.afterEach ? `  afterEach(() => {
    ${suite.afterEach}
  });
` : ""}
  ${tests}
});
`;
  }
  formatTestCase(test) {
    return `it('${test.name}', () => {
${test.setup ? `    // Arrange
    ${test.setup}
` : ""}
    // Act
    ${test.action}

    // Assert
    ${test.assertion}
${test.cleanup ? `
    // Cleanup
    ${test.cleanup}` : ""}
  })`;
  }
  generateImports(targetPath, sourceFile) {
    const imports = [
      `import { describe, it, expect, beforeEach, afterEach } from 'vitest';`
    ];
    const relativePath = this.getRelativePath(
      this.getTestPath(targetPath),
      targetPath
    );
    const exportedNames = this.getExportedNames(sourceFile);
    if (exportedNames.length > 0) {
      imports.push(
        `import { ${exportedNames.join(", ")} } from '${relativePath}';`
      );
    }
    return imports;
  }
  getExportedNames(sourceFile) {
    const exports = [];
    const visit = (node) => {
      if (ts.isFunctionDeclaration(node) && node.name && this.isExported(node)) {
        exports.push(node.name.getText());
      }
      if (ts.isClassDeclaration(node) && node.name && this.isExported(node)) {
        exports.push(node.name.getText());
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
    return exports;
  }
  isExported(node) {
    return node.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword) || false;
  }
  getTestPath(targetPath) {
    const relativePath = targetPath.replace(this.projectRoot, "");
    const pathParts = relativePath.split("/");
    const fileName = pathParts.pop();
    const testFileName = fileName?.replace(".ts", ".test.ts");
    return join(
      this.projectRoot,
      "src",
      "__tests__",
      ...pathParts.slice(2),
      testFileName || ""
    );
  }
  getIntegrationTestPath(modulePath) {
    const moduleName = basename(modulePath);
    return join(
      this.testDir,
      "integration",
      `${moduleName}.integration.test.ts`
    );
  }
  getModuleName(targetPath) {
    const fileName = basename(targetPath);
    return fileName.replace(/\.(ts|js)$/, "");
  }
  getRelativePath(from, to) {
    const fromParts = from.split("/");
    const toParts = to.split("/");
    let i = 0;
    while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) {
      i++;
    }
    const upCount = fromParts.length - i - 1;
    const ups = Array(upCount).fill("..");
    const downs = toParts.slice(i);
    const relativePath = [...ups, ...downs].join("/");
    return relativePath.replace(/\.ts$/, ".js");
  }
  calculateCoverage(coverageData) {
    const values = Object.values(coverageData);
    const total = values.length;
    const covered = values.filter((v) => v > 0).length;
    const percentage = total > 0 ? covered / total * 100 : 0;
    return { total, covered, percentage: Math.round(percentage) };
  }
  findUncoveredLines(statementMap, statements) {
    const uncovered = [];
    Object.entries(statements).forEach(([key, value]) => {
      if (value === 0 && statementMap[key]) {
        const loc = statementMap[key].start;
        uncovered.push(loc.line);
      }
    });
    return uncovered;
  }
  extractFailures(results) {
    const failures = [];
    if (results.testResults) {
      const testResults = results.testResults;
      testResults.forEach((suite) => {
        suite.assertionResults?.forEach((test) => {
          if (test.status === "failed") {
            failures.push({
              test: test.title,
              error: test.failureMessages?.join("\n") || "Unknown error"
            });
          }
        });
      });
    }
    return failures;
  }
  // Mock and fixture generation helpers
  generateMockImplementation(schema) {
    return `export const mock${schema.name || "Data"} = {
  ${this.generateMockProperties(schema)}
};`;
  }
  generateMockProperties(schema) {
    if (!schema.properties) return "";
    const properties = schema.properties;
    return Object.entries(properties).map(([key, value]) => {
      return `${key}: ${this.generateMockValue(value.type, value)}`;
    }).join(",\n  ");
  }
  generateMockValue(type, _schema) {
    switch (type) {
      case "string":
        return `'mock-value'`;
      case "number":
        return `${Math.floor(Math.random() * 100)}`;
      case "boolean":
        return "true";
      case "array":
        return "[]";
      case "object":
        return "{}";
      default:
        return "null";
    }
  }
  inferTypeFromSchema(schema) {
    if (typeof schema === "object" && schema !== null && "type" in schema) {
      return schema.type;
    }
    if (Array.isArray(schema)) return "array";
    if (typeof schema === "object") return "object";
    return typeof schema;
  }
  findDependencies(sourceFile, dependencies) {
    const visit = (node) => {
      if (ts.isImportDeclaration(node)) {
        const moduleSpecifier = node.moduleSpecifier;
        if (ts.isStringLiteral(moduleSpecifier)) {
          dependencies.add(moduleSpecifier.text);
        }
      }
      ts.forEachChild(node, visit);
    };
    visit(sourceFile);
  }
  generateModuleIntegrationTests(modulePath, _dependencies) {
    const tests = [];
    const moduleName = basename(modulePath);
    tests.push({
      name: `should initialize ${moduleName} module`,
      description: `Test module initialization`,
      action: `const module = await import('${modulePath}');`,
      assertion: `expect(module).toBeDefined();`,
      isAsync: true
    });
    return tests;
  }
  generateIntegrationImports(modulePath, dependencies) {
    const imports = [
      `import { describe, it, expect, beforeEach, afterEach } from 'vitest';`
    ];
    dependencies.forEach((dep) => {
      if (!dep.startsWith(".")) {
        const importName = dep.replace(/[^a-zA-Z]/g, "");
        imports.push(`import * as ${importName} from '${dep}';`);
      }
    });
    return imports;
  }
  generateIntegrationSetup(_dependencies) {
    return "const testContext = {};";
  }
  generateIntegrationCleanup() {
    return "// Reset any global state";
  }
  generateBeforeEach(classes) {
    if (classes.length === 0) return void 0;
    return "// Setup test environment";
  }
  generateAfterEach(classes) {
    if (classes.length === 0) return void 0;
    return "// Cleanup test environment";
  }
  findFunction(sourceFile, functionName) {
    let result;
    const visit = (node) => {
      if (ts.isFunctionDeclaration(node) && node.name?.getText() === functionName) {
        result = node;
      }
      if (!result) {
        ts.forEachChild(node, visit);
      }
    };
    visit(sourceFile);
    return result;
  }
  generateDefaultProps() {
    return {
      id: "test-id",
      className: "test-class",
      children: "Test Content"
    };
  }
  generateEdgeCaseProps() {
    return {
      id: "",
      className: null,
      children: void 0
    };
  }
  generateTestData() {
    return {
      items: [
        { id: 1, name: "Item 1" },
        { id: 2, name: "Item 2" }
      ],
      config: {
        enabled: true,
        limit: 10
      }
    };
  }
  generateFixtureSetup(componentName) {
    return `// Setup ${componentName} fixture`;
  }
  generateFixtureTeardown(componentName) {
    return `// Teardown ${componentName} fixture`;
  }
  generateBenchmarkCode(targetPath, functionName) {
    return `import { bench, describe } from 'vitest';
import { ${functionName} } from '${targetPath}';

describe('${functionName} performance', () => {
  bench('${functionName} execution time', () => {
    ${functionName}();
  });
});`;
  }
  parseBenchmarkResults(results, functionName) {
    return {
      function: functionName,
      averageTime: results.mean || 0,
      minTime: results.min || 0,
      maxTime: results.max || 0,
      iterations: results.samples || 0,
      memoryUsage: results.memory || 0
    };
  }
}
export {
  TestingAgent
};
//# sourceMappingURL=testing-agent.js.map
