import { beforeEach, describe, expect, it, mock } from 'bun:test';
import { QueueManager } from '../src/queue-manager';
import type { QueueManagerConfig, RedisConfig } from '../src/types';

describe.skip('QueueManager', () => {
  // Skipping these tests as they require real Redis connection
  // TODO: Create mock implementation or use testcontainers

  const mockRedisConfig: RedisConfig = {
    host: 'localhost',
    port: 6379,
  };

  const mockLogger = {
    info: mock(() => {}),
    error: mock(() => {}),
    warn: mock(() => {}),
    debug: mock(() => {}),
    trace: mock(() => {}),
  };

  describe('constructor', () => {
    it('should create queue manager with default config', () => {
      const manager = new QueueManager(mockRedisConfig);
      expect(manager).toBeDefined();
    });

    it('should create queue manager with custom config', () => {
      const config: QueueManagerConfig = {
        defaultJobOptions: {
          attempts: 5,
          removeOnComplete: 50,
        },
        enableMetrics: true,
        enableScheduler: true,
      };

      const manager = new QueueManager(mockRedisConfig, config, mockLogger);
      expect(manager).toBeDefined();
    });
  });

  describe('queue operations', () => {
    let manager: QueueManager;

    beforeEach(() => {
      manager = new QueueManager(mockRedisConfig, {}, mockLogger);
    });

    it('should create or get queue', () => {
      const queue = manager.createQueue('test-queue');
      expect(queue).toBeDefined();
      expect(queue.getName()).toBe('test-queue');
    });

    it('should return same queue instance', () => {
      const queue1 = manager.createQueue('test-queue');
      const queue2 = manager.createQueue('test-queue');
      expect(queue1).toBe(queue2);
    });

    it('should create queue with options', () => {
      const queue = manager.createQueue('test-queue', {
        concurrency: 5,
        workers: 2,
      });
      expect(queue).toBeDefined();
    });

    it('should get existing queue', () => {
      manager.createQueue('test-queue');
      const queue = manager.getQueue('test-queue');
      expect(queue).toBeDefined();
    });

    it('should return undefined for non-existent queue', () => {
      const queue = manager.getQueue('non-existent');
      expect(queue).toBeUndefined();
    });

    it('should list all queues', () => {
      manager.createQueue('queue1');
      manager.createQueue('queue2');
      const queues = manager.getQueues();
      expect(queues).toHaveLength(2);
      expect(queues.map(q => q.getName())).toContain('queue1');
      expect(queues.map(q => q.getName())).toContain('queue2');
    });

    it('should check if queue exists', () => {
      manager.createQueue('test-queue');
      expect(manager.hasQueue('test-queue')).toBe(true);
      expect(manager.hasQueue('non-existent')).toBe(false);
    });
  });

  describe('cache operations', () => {
    let manager: QueueManager;

    beforeEach(() => {
      manager = new QueueManager(mockRedisConfig, {}, mockLogger);
    });

    it('should create cache', () => {
      const cache = manager.createCache('test-cache');
      expect(cache).toBeDefined();
    });

    it('should get existing cache', () => {
      manager.createCache('test-cache');
      const cache = manager.getCache('test-cache');
      expect(cache).toBeDefined();
    });

    it('should return same cache instance', () => {
      const cache1 = manager.createCache('test-cache');
      const cache2 = manager.createCache('test-cache');
      expect(cache1).toBe(cache2);
    });
  });

  describe('service discovery', () => {
    let manager: QueueManager;

    beforeEach(() => {
      manager = new QueueManager(mockRedisConfig, {}, mockLogger);
    });

    it('should configure service name', () => {
      manager.configureService('test-service');
      expect((manager as any).serviceName).toBe('test-service');
    });

    it('should register queue route', () => {
      manager.configureService('test-service');
      manager.registerQueueRoute({
        service: 'remote-service',
        handler: 'process',
        queueName: '{remote-service_process}',
      });

      expect(manager.hasRoute('remote-service', 'process')).toBe(true);
    });

    it('should send to remote queue', async () => {
      manager.configureService('test-service');
      manager.registerQueueRoute({
        service: 'remote-service',
        handler: 'process',
        queueName: '{remote-service_process}',
      });

      const jobId = await manager.sendToQueue('remote-service', 'process', { data: 'test' });
      expect(jobId).toBeDefined();
    });

    it('should send to local queue', async () => {
      manager.configureService('test-service');
      manager.createQueue('{test-service_process}');

      const jobId = await manager.sendToQueue('test-service', 'process', { data: 'test' });
      expect(jobId).toBeDefined();
    });
  });

  describe('shutdown', () => {
    it('should shutdown gracefully', async () => {
      const manager = new QueueManager(mockRedisConfig, {}, mockLogger);
      manager.createQueue('test-queue');

      await manager.shutdown();
      expect((manager as any).isShuttingDown).toBe(true);
    });

    it('should handle multiple shutdown calls', async () => {
      const manager = new QueueManager(mockRedisConfig, {}, mockLogger);

      const promise1 = manager.shutdown();
      const promise2 = manager.shutdown();

      expect(promise1).toBe(promise2);
      await promise1;
    });
  });

  describe('metrics', () => {
    it('should get global stats', async () => {
      const manager = new QueueManager(
        mockRedisConfig,
        {
          enableMetrics: true,
        },
        mockLogger
      );

      manager.createQueue('queue1');
      manager.createQueue('queue2');

      const stats = await manager.getGlobalStats();
      expect(stats).toBeDefined();
      expect(stats.totalQueues).toBe(2);
    });

    it('should get queue stats', async () => {
      const manager = new QueueManager(
        mockRedisConfig,
        {
          enableMetrics: true,
        },
        mockLogger
      );

      const queue = manager.createQueue('test-queue');
      const stats = await manager.getQueueStats('test-queue');

      expect(stats).toBeDefined();
      expect(stats.name).toBe('test-queue');
    });
  });

  describe('rate limiting', () => {
    it('should apply rate limit rules', () => {
      const manager = new QueueManager(
        mockRedisConfig,
        {
          rateLimiter: {
            rules: [
              {
                name: 'api-limit',
                max: 100,
                duration: 60000,
                scope: 'global',
              },
            ],
          },
        },
        mockLogger
      );

      const rateLimiter = (manager as any).rateLimiter;
      expect(rateLimiter).toBeDefined();
    });
  });
});
