/**
 * AgentOrchestrator Tests
 * Tests for the agent orchestration system
 */

import { AgentOrchestrator, getOrchestrator } from '../../../lib/agents/AgentOrchestrator';

// Mock all agents
jest.mock('../../../lib/agents/PlantLineageAgent', () => ({
  PlantLineageAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'plant-lineage-agent', name: 'Plant Lineage Agent', priority: 'high' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'plant-lineage-agent',
      tasksCompleted: 5,
      tasksFailed: 0,
      averageExecutionMs: 100,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getPlantLineageAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/TransportTrackerAgent', () => ({
  TransportTrackerAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'transport-tracker-agent', name: 'Transport Tracker Agent', priority: 'high' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'transport-tracker-agent',
      tasksCompleted: 3,
      tasksFailed: 1,
      averageExecutionMs: 150,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getTransportTrackerAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/DemandForecastAgent', () => ({
  DemandForecastAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'demand-forecast-agent', name: 'Demand Forecast Agent', priority: 'high' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'demand-forecast-agent',
      tasksCompleted: 2,
      tasksFailed: 0,
      averageExecutionMs: 200,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getDemandForecastAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/VerticalFarmAgent', () => ({
  VerticalFarmAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'vertical-farm-agent', name: 'Vertical Farm Agent', priority: 'critical' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'vertical-farm-agent',
      tasksCompleted: 10,
      tasksFailed: 0,
      averageExecutionMs: 50,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getVerticalFarmAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/EnvironmentAnalysisAgent', () => ({
  EnvironmentAnalysisAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'environment-analysis-agent', name: 'Environment Analysis Agent', priority: 'medium' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'environment-analysis-agent',
      tasksCompleted: 1,
      tasksFailed: 0,
      averageExecutionMs: 300,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getEnvironmentAnalysisAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/MarketMatchingAgent', () => ({
  MarketMatchingAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'market-matching-agent', name: 'Market Matching Agent', priority: 'high' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'market-matching-agent',
      tasksCompleted: 4,
      tasksFailed: 0,
      averageExecutionMs: 120,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getMarketMatchingAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/SustainabilityAgent', () => ({
  SustainabilityAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'sustainability-agent', name: 'Sustainability Agent', priority: 'medium' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'sustainability-agent',
      tasksCompleted: 1,
      tasksFailed: 0,
      averageExecutionMs: 400,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getSustainabilityAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/NetworkDiscoveryAgent', () => ({
  NetworkDiscoveryAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'network-discovery-agent', name: 'Network Discovery Agent', priority: 'medium' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'network-discovery-agent',
      tasksCompleted: 1,
      tasksFailed: 0,
      averageExecutionMs: 500,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getNetworkDiscoveryAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/QualityAssuranceAgent', () => ({
  QualityAssuranceAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'quality-assurance-agent', name: 'Quality Assurance Agent', priority: 'critical' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'quality-assurance-agent',
      tasksCompleted: 8,
      tasksFailed: 0,
      averageExecutionMs: 80,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getQualityAssuranceAgent: jest.fn(),
}));

jest.mock('../../../lib/agents/GrowerAdvisoryAgent', () => ({
  GrowerAdvisoryAgent: jest.fn().mockImplementation(() => ({
    config: { id: 'grower-advisory-agent', name: 'Grower Advisory Agent', priority: 'high' },
    status: 'idle',
    start: jest.fn().mockResolvedValue(undefined),
    stop: jest.fn().mockResolvedValue(undefined),
    getMetrics: jest.fn().mockReturnValue({
      agentId: 'grower-advisory-agent',
      tasksCompleted: 6,
      tasksFailed: 1,
      averageExecutionMs: 180,
      errors: [],
    }),
    getAlerts: jest.fn().mockReturnValue([]),
  })),
  getGrowerAdvisoryAgent: jest.fn(),
}));

describe('AgentOrchestrator', () => {
  let orchestrator: AgentOrchestrator;

  beforeEach(() => {
    // Reset singleton
    (globalThis as any).__orchestratorInstance = undefined;
    orchestrator = new AgentOrchestrator();
  });

  afterEach(async () => {
    const status = orchestrator.getStatus();
    if (status.isRunning) {
      await orchestrator.stopAll();
    }
  });

  describe('Initialization', () => {
    it('should initialize with all 10 agents', () => {
      const status = orchestrator.getStatus();
      expect(status.totalAgents).toBe(10);
    });

    it('should not be running initially', () => {
      const status = orchestrator.getStatus();
      expect(status.isRunning).toBe(false);
    });

    it('should have no running agents initially', () => {
      const status = orchestrator.getStatus();
      expect(status.runningAgents).toBe(0);
    });
  });

  describe('Starting Agents', () => {
    it('should start all agents', async () => {
      await orchestrator.startAll();
      const status = orchestrator.getStatus();
      expect(status.isRunning).toBe(true);
    });

    it('should start individual agent', async () => {
      await orchestrator.startAgent('plant-lineage-agent');
      const health = orchestrator.getAgentHealth('plant-lineage-agent');
      expect(health).toBeDefined();
    });
  });

  describe('Stopping Agents', () => {
    it('should stop all agents', async () => {
      await orchestrator.startAll();
      await orchestrator.stopAll();
      const status = orchestrator.getStatus();
      expect(status.isRunning).toBe(false);
    });

    it('should stop individual agent', async () => {
      await orchestrator.startAgent('plant-lineage-agent');
      await orchestrator.stopAgent('plant-lineage-agent');
      // Agent should be stopped
    });
  });

  describe('Agent Health', () => {
    it('should return health for existing agent', async () => {
      await orchestrator.startAll();
      const health = orchestrator.getAgentHealth('plant-lineage-agent');
      expect(health).toHaveProperty('agentId');
      expect(health?.agentId).toBe('plant-lineage-agent');
    });

    it('should return undefined for non-existent agent', () => {
      const health = orchestrator.getAgentHealth('non-existent-agent');
      expect(health).toBeUndefined();
    });
  });

  describe('Status', () => {
    it('should return correct status structure', () => {
      const status = orchestrator.getStatus();
      expect(status).toHaveProperty('isRunning');
      expect(status).toHaveProperty('totalAgents');
      expect(status).toHaveProperty('runningAgents');
      expect(status).toHaveProperty('healthyAgents');
    });

    it('should track uptime when running', async () => {
      await orchestrator.startAll();
      await new Promise((resolve) => setTimeout(resolve, 50));
      const status = orchestrator.getStatus();
      expect(status.uptime).toBeGreaterThan(0);
    });
  });

  describe('Dashboard', () => {
    it('should return dashboard data', async () => {
      await orchestrator.startAll();
      const dashboard = orchestrator.getDashboard();
      expect(dashboard).toHaveProperty('status');
      expect(dashboard).toHaveProperty('agents');
      expect(dashboard).toHaveProperty('recentAlerts');
    });

    it('should include all agents in dashboard', async () => {
      await orchestrator.startAll();
      const dashboard = orchestrator.getDashboard();
      expect(dashboard.agents.length).toBe(10);
    });
  });

  describe('Alerts', () => {
    it('should return empty alerts initially', () => {
      const alerts = orchestrator.getAlerts();
      expect(alerts).toEqual([]);
    });

    it('should filter alerts by severity', () => {
      const criticalAlerts = orchestrator.getAlerts('critical');
      expect(Array.isArray(criticalAlerts)).toBe(true);
    });
  });

  describe('Singleton', () => {
    it('should return same instance from getOrchestrator', () => {
      const orch1 = getOrchestrator();
      const orch2 = getOrchestrator();
      expect(orch1).toBe(orch2);
    });
  });
});
