/**
 * Tests for Performance Tools
 *
 * Tests the performance monitoring and analytics tools for WordPress sites.
 */

import { describe, it, expect, vi, beforeEach, afterEach } from "vitest";

// Mock dependencies BEFORE importing the class
const mockLogger = {
  info: vi.fn(),
  warn: vi.fn(),
  error: vi.fn(),
  debug: vi.fn(),
  time: vi.fn().mockImplementation((name, fn) => fn()),
  child: vi.fn().mockReturnThis(),
};

vi.mock("../../dist/utils/logger.js", () => ({
  LoggerFactory: {
    performance: vi.fn(() => mockLogger),
    server: vi.fn(() => mockLogger),
    tool: vi.fn(() => mockLogger),
  },
}));

// Mock the performance dependencies
vi.mock("../../dist/performance/PerformanceMonitor.js", () => ({
  PerformanceMonitor: vi.fn(function () {
    return {
      startMonitoring: vi.fn().mockResolvedValue({ status: "monitoring_started" }),
      stopMonitoring: vi.fn().mockResolvedValue({ status: "monitoring_stopped" }),
      getCurrentMetrics: vi.fn().mockResolvedValue({
        timestamp: Date.now(),
        responseTime: 250,
        memoryUsage: 85.5,
        cacheHitRate: 0.85,
        activeConnections: 12,
      }),
      getAlerts: vi.fn().mockReturnValue([]),
      getHistoricalData: vi.fn().mockReturnValue([
        {
          requests: { total: 90, failed: 1, averageResponseTime: 240 },
          cache: { hitRate: 0.8 },
          system: { uptime: 86300000 },
        },
      ]),
    };
  }),
}));

const mockMetricsCollector = {
  collect: vi.fn().mockResolvedValue({
    serverMetrics: { cpu: 45.2, memory: 78.8, disk: 62.1 },
    wordpressMetrics: { queryTime: 0.123, pluginLoadTime: 0.045 },
  }),
  getHistoricalData: vi.fn().mockResolvedValue([]),
  registerClient: vi.fn(),
  registerCacheManager: vi.fn(),
  collectCurrentMetrics: vi.fn().mockReturnValue({
    requests: {
      total: 100,
      failed: 2,
      averageResponseTime: 250,
      requestsPerSecond: 10,
      p50ResponseTime: 200,
      p95ResponseTime: 400,
      p99ResponseTime: 600,
    },
    cache: { hitRate: 0.85, totalSize: 1024, evictions: 5, memoryUsageMB: 50 },
    system: { memoryUsage: 70, cpuUsage: 45, uptime: 86400000 },
    tools: { mostUsedTool: "wp_posts_list", toolUsageCount: {}, toolPerformance: {} },
  }),
  getSiteMetrics: vi.fn().mockReturnValue({ isActive: true, cache: {}, client: {} }),
  getAggregatedCacheStats: vi.fn().mockReturnValue({}),
  getAggregatedClientStats: vi.fn().mockReturnValue({}),
  compareSitePerformance: vi.fn().mockReturnValue({}),
};

vi.mock("../../dist/performance/MetricsCollector.js", () => ({
  MetricsCollector: vi.fn(function () {
    return mockMetricsCollector;
  }),
}));

vi.mock("../../dist/performance/PerformanceAnalytics.js", () => ({
  PerformanceAnalytics: vi.fn(function () {
    return {
      analyzeTrends: vi.fn().mockReturnValue([{ metric: "responseTime", direction: "improving", change: -5.2 }]),
      detectAnomalies: vi.fn().mockResolvedValue([]),
      generateReport: vi.fn().mockResolvedValue({
        summary: "Performance is within normal parameters",
        recommendations: [],
      }),
      addDataPoint: vi.fn(),
      benchmarkPerformance: vi.fn().mockReturnValue([{ category: "Response Time", status: "good", improvement: 0 }]),
      generateInsights: vi.fn().mockReturnValue([
        {
          category: "optimization",
          title: "Test",
          description: "Test",
          priority: "medium",
          estimatedImprovement: 10,
          implementationEffort: "low",
        },
      ]),
      generateOptimizationPlan: vi.fn().mockReturnValue({
        quickWins: [],
        mediumTerm: [],
        longTerm: [],
        estimatedROI: { timeframe: "3months", improvement: 25 },
      }),
      predictPerformance: vi.fn().mockReturnValue({ prediction: "stable" }),
      exportAnalyticsReport: vi.fn().mockReturnValue({
        summary: {},
        trends: [],
        benchmarks: [],
        insights: [],
        anomalies: [],
        predictions: {},
        optimizationPlan: {},
      }),
      getAnomalies: vi.fn().mockReturnValue([]),
    };
  }),
}));

// Note: logger already mocked above

// Mock toolWrapper — use a plain function (not vi.fn()) so mockReset: true
// in vitest.config.ts cannot clear the implementation between tests.
vi.mock("../../dist/utils/toolWrapper.js", () => ({
  toolWrapper: (fn) => fn(),
}));

// Mock config helpers
vi.mock("../../dist/config/Config.js", () => ({
  ConfigHelpers: {
    shouldDebug: vi.fn(() => false),
    isProd: vi.fn(() => false),
    isDev: vi.fn(() => false),
    isTest: vi.fn(() => true),
    isCI: vi.fn(() => false),
    get: vi.fn(() => ({
      get: vi.fn(() => ({
        app: { nodeEnv: "test" },
      })),
    })),
  },
}));

// Import after mocks
let PerformanceTools;

beforeEach(async () => {
  // Clear all mocks first
  vi.clearAllMocks();

  // Dynamically import the class to ensure mocks are applied
  const module = await import("../../dist/tools/performance.js");
  PerformanceTools = module.default;
});

describe("PerformanceTools", () => {
  let performanceTools;
  let _mockClient;

  beforeEach(async () => {
    _mockClient = {
      get: vi.fn(),
      post: vi.fn(),
      baseUrl: "https://test.example.com",
    };

    // Ensure PerformanceTools is available
    if (!PerformanceTools) {
      const module = await import("../../dist/tools/performance.js");
      PerformanceTools = module.default;
    }

    // Create PerformanceTools without clients to avoid dependency issues
    performanceTools = new PerformanceTools();
    vi.clearAllMocks();
  });

  afterEach(() => {
    vi.restoreAllMocks();
  });

  describe("Constructor", () => {
    it("should initialize with clients map", () => {
      expect(performanceTools).toBeDefined();
      // PerformanceTools doesn't expose clients directly - check via monitoring components
      expect(performanceTools.monitor).toBeDefined();
    });

    it("should initialize monitoring components", () => {
      expect(performanceTools.monitor).toBeDefined();
      expect(performanceTools.collector).toBeDefined();
      expect(performanceTools.analytics).toBeDefined();
    });
  });

  describe("getTools", () => {
    it("should return an array of tool definitions", () => {
      const tools = performanceTools.getTools();

      expect(Array.isArray(tools)).toBe(true);
      expect(tools.length).toBeGreaterThan(0);

      // Check that each tool has required properties
      tools.forEach((tool) => {
        expect(tool.name).toBeDefined();
        expect(tool.description).toBeDefined();
        expect(typeof tool.handler).toBe("function");
      });
    });

    it("should include expected performance tools", () => {
      const tools = performanceTools.getTools();
      const toolNames = tools.map((tool) => tool.name);

      // Check the actual tool names from the implementation
      expect(toolNames).toContain("wp_performance_stats");
      expect(toolNames).toContain("wp_performance_history");
      expect(toolNames).toContain("wp_performance_benchmark");
      expect(toolNames).toContain("wp_performance_alerts");
      expect(toolNames).toContain("wp_performance_optimize");
      expect(toolNames).toContain("wp_performance_export");
    });
  });

  describe("Performance Monitoring", () => {
    it("should have performance monitoring tools available", () => {
      const tools = performanceTools.getTools();
      const monitoringToolNames = tools.map((t) => t.name);

      expect(monitoringToolNames).toContain("wp_performance_stats");
      expect(monitoringToolNames).toContain("wp_performance_history");
      expect(monitoringToolNames).toContain("wp_performance_benchmark");
    });

    it("should call tool handlers through tool registry", async () => {
      const tools = performanceTools.getTools();
      const statsTools = tools.find((t) => t.name === "wp_performance_stats");

      expect(statsTools).toBeDefined();
      expect(typeof statsTools.handler).toBe("function");

      // Note: We can't easily test the handler without a full tool invocation system
      // This test verifies the tool structure is correct
    });
  });

  describe("Metrics Collection", () => {
    it("should have metrics collection tools", () => {
      const tools = performanceTools.getTools();
      const metricsToolNames = tools.map((t) => t.name);

      expect(metricsToolNames).toContain("wp_performance_stats");
      expect(metricsToolNames).toContain("wp_performance_history");
    });

    it("should configure tool parameters correctly", () => {
      const tools = performanceTools.getTools();
      const historyTool = tools.find((t) => t.name === "wp_performance_history");

      expect(historyTool).toBeDefined();
      expect(historyTool.parameters).toBeDefined();
      expect(Array.isArray(historyTool.parameters)).toBe(true);

      const parameterNames = historyTool.parameters.map((p) => p.name);
      expect(parameterNames).toContain("timeframe");
      expect(parameterNames).toContain("metrics");
    });
  });

  describe("Performance Analytics", () => {
    it("should have analytics tools", () => {
      const tools = performanceTools.getTools();
      const analyticsToolNames = tools.map((t) => t.name);

      expect(analyticsToolNames).toContain("wp_performance_benchmark");
      expect(analyticsToolNames).toContain("wp_performance_alerts");
      expect(analyticsToolNames).toContain("wp_performance_optimize");
    });

    it("should configure benchmark tool parameters", () => {
      const tools = performanceTools.getTools();
      const benchmarkTool = tools.find((t) => t.name === "wp_performance_benchmark");

      expect(benchmarkTool).toBeDefined();
      expect(benchmarkTool.description).toContain("benchmark");
      expect(benchmarkTool.parameters).toBeDefined();

      const parameterNames = benchmarkTool.parameters.map((p) => p.name);
      expect(parameterNames).toContain("category");
      expect(parameterNames).toContain("includeRecommendations");
    });
  });

  describe("Error Handling", () => {
    it("should handle initialization with undefined clients", () => {
      expect(() => new PerformanceTools()).not.toThrow();
      const toolsWithoutClients = new PerformanceTools();
      expect(toolsWithoutClients.monitor).toBeDefined();
      expect(toolsWithoutClients.collector).toBeDefined();
      expect(toolsWithoutClients.analytics).toBeDefined();
    });

    it("should handle empty clients map", () => {
      expect(() => new PerformanceTools(new Map())).not.toThrow();
      const toolsWithEmptyMap = new PerformanceTools(new Map());
      expect(toolsWithEmptyMap.getTools()).toBeDefined();
      expect(toolsWithEmptyMap.getTools().length).toBeGreaterThan(0);
    });
  });

  describe("Parameter Validation", () => {
    it("should define tools with proper parameter structure", () => {
      const tools = performanceTools.getTools();

      tools.forEach((tool) => {
        expect(tool.parameters).toBeDefined();
        expect(Array.isArray(tool.parameters)).toBe(true);

        // Each parameter should have required properties
        tool.parameters.forEach((param) => {
          expect(param.name).toBeDefined();
          expect(param.type).toBeDefined();
          expect(param.description).toBeDefined();
          expect(typeof param.required).toBe("boolean");
        });
      });
    });

    it("should have consistent site parameter across tools", () => {
      const tools = performanceTools.getTools();

      tools.forEach((tool) => {
        const siteParam = tool.parameters.find((p) => p.name === "site");
        if (siteParam) {
          expect(siteParam.type).toBe("string");
          expect(siteParam.required).toBe(false);
          expect(siteParam.description).toContain("multi-site");
        }
      });
    });
  });

  describe("Integration", () => {
    it("should work with different WordPress client configurations", () => {
      // Test without clients to avoid dependency injection issues
      const altTools = new PerformanceTools();
      expect(altTools.monitor).toBeDefined();
      expect(altTools.collector).toBeDefined();
      expect(altTools.analytics).toBeDefined();
    });

    it("should maintain consistent tool definitions", () => {
      const tools1 = performanceTools.getTools();
      const tools2 = performanceTools.getTools();

      expect(tools1.length).toBe(tools2.length);
      expect(tools1.map((t) => t.name)).toEqual(tools2.map((t) => t.name));
    });
  });

  describe("wp_performance_benchmark timeout regression", () => {
    it("should resolve within 1s (never hang)", async () => {
      const tools = performanceTools.getTools();
      const benchmarkTool = tools.find((t) => t.name === "wp_performance_benchmark");

      const start = Date.now();
      const result = await benchmarkTool.handler({}, { category: "all", includeRecommendations: true });
      expect(Date.now() - start).toBeLessThan(1000);
      expect(result).toBeDefined();
    });

    it("should return a graceful error when analytics.benchmarkPerformance throws", async () => {
      // Re-import to get a fresh instance with failing analytics
      const module = await import("../../dist/tools/performance.js");
      const FreshPerformanceTools = module.default;
      const freshTools = new FreshPerformanceTools();

      // Override the analytics mock to throw
      freshTools.analytics.benchmarkPerformance = vi.fn().mockImplementation(() => {
        throw new Error("benchmark engine failure");
      });

      const tools = freshTools.getTools();
      const benchmarkTool = tools.find((t) => t.name === "wp_performance_benchmark");
      const result = await benchmarkTool.handler({}, {});

      // With the toolWrapper mock, the result is the inner async function.
      // This test mainly verifies no unhandled rejection occurs.
      expect(result).toBeDefined();
    });
  });
});
