import { describe, expect, it } from 'bun:test';
import type {
  CachePoolConfig,
  ConnectionFactory,
  ConnectionFactoryConfig,
  ConnectionPool,
  ConnectionPoolConfig,
  GenericClientConfig,
  MongoDBPoolConfig,
  PoolMetrics,
  PostgreSQLPoolConfig,
  QueuePoolConfig,
} from '../src/types';

describe('DI Types', () => {
  describe('GenericClientConfig', () => {
    it('should allow any key-value pairs', () => {
      const config: GenericClientConfig = {
        host: 'localhost',
        port: 5432,
        username: 'test',
        password: 'test',
        customOption: true,
      };

      expect(config.host).toBe('localhost');
      expect(config.port).toBe(5432);
      expect(config.customOption).toBe(true);
    });
  });

  describe('ConnectionPoolConfig', () => {
    it('should have required and optional fields', () => {
      const config: ConnectionPoolConfig = {
        name: 'test-pool',
        poolSize: 10,
        minConnections: 2,
        maxConnections: 20,
        idleTimeoutMillis: 30000,
        connectionTimeoutMillis: 5000,
        enableMetrics: true,
      };

      expect(config.name).toBe('test-pool');
      expect(config.poolSize).toBe(10);
      expect(config.enableMetrics).toBe(true);
    });

    it('should allow minimal configuration', () => {
      const config: ConnectionPoolConfig = {
        name: 'minimal-pool',
      };

      expect(config.name).toBe('minimal-pool');
      expect(config.poolSize).toBeUndefined();
    });
  });

  describe('Specific Pool Configs', () => {
    it('should extend ConnectionPoolConfig for MongoDB', () => {
      const config: MongoDBPoolConfig = {
        name: 'mongo-pool',
        poolSize: 5,
        config: {
          uri: 'mongodb://localhost:27017',
          database: 'test',
        },
      };

      expect(config.name).toBe('mongo-pool');
      expect(config.config.uri).toBe('mongodb://localhost:27017');
    });

    it('should extend ConnectionPoolConfig for PostgreSQL', () => {
      const config: PostgreSQLPoolConfig = {
        name: 'postgres-pool',
        config: {
          host: 'localhost',
          port: 5432,
          database: 'test',
        },
      };

      expect(config.name).toBe('postgres-pool');
      expect(config.config.host).toBe('localhost');
    });

    it('should extend ConnectionPoolConfig for Cache', () => {
      const config: CachePoolConfig = {
        name: 'cache-pool',
        config: {
          host: 'localhost',
          port: 6379,
        },
      };

      expect(config.name).toBe('cache-pool');
      expect(config.config.port).toBe(6379);
    });

    it('should extend ConnectionPoolConfig for Queue', () => {
      const config: QueuePoolConfig = {
        name: 'queue-pool',
        config: {
          redis: {
            host: 'localhost',
            port: 6379,
          },
        },
      };

      expect(config.name).toBe('queue-pool');
      expect(config.config.redis.host).toBe('localhost');
    });
  });

  describe('ConnectionFactoryConfig', () => {
    it('should define factory configuration', () => {
      const config: ConnectionFactoryConfig = {
        service: 'test-service',
        environment: 'development',
        pools: {
          mongodb: {
            poolSize: 10,
          },
          postgres: {
            maxConnections: 20,
          },
          cache: {
            idleTimeoutMillis: 60000,
          },
          queue: {
            enableMetrics: true,
          },
        },
      };

      expect(config.service).toBe('test-service');
      expect(config.environment).toBe('development');
      expect(config.pools?.mongodb?.poolSize).toBe(10);
      expect(config.pools?.postgres?.maxConnections).toBe(20);
    });

    it('should allow minimal factory config', () => {
      const config: ConnectionFactoryConfig = {
        service: 'minimal-service',
        environment: 'test',
      };

      expect(config.service).toBe('minimal-service');
      expect(config.pools).toBeUndefined();
    });
  });

  describe('ConnectionPool', () => {
    it('should define connection pool interface', () => {
      const mockPool: ConnectionPool<any> = {
        name: 'test-pool',
        client: { connected: true },
        metrics: {
          created: new Date(),
          totalConnections: 10,
          activeConnections: 5,
          idleConnections: 5,
          waitingRequests: 0,
          errors: 0,
        },
        health: async () => true,
        dispose: async () => {},
      };

      expect(mockPool.name).toBe('test-pool');
      expect(mockPool.client.connected).toBe(true);
      expect(mockPool.metrics.totalConnections).toBe(10);
    });
  });

  describe('PoolMetrics', () => {
    it('should define pool metrics structure', () => {
      const metrics: PoolMetrics = {
        created: new Date('2024-01-01'),
        totalConnections: 100,
        activeConnections: 25,
        idleConnections: 75,
        waitingRequests: 2,
        errors: 3,
      };

      expect(metrics.totalConnections).toBe(100);
      expect(metrics.activeConnections).toBe(25);
      expect(metrics.idleConnections).toBe(75);
      expect(metrics.waitingRequests).toBe(2);
      expect(metrics.errors).toBe(3);
    });
  });

  describe('ConnectionFactory', () => {
    it('should define connection factory interface', () => {
      const mockFactory: ConnectionFactory = {
        createMongoDB: async config => ({
          name: config.name,
          client: {},
          metrics: {
            created: new Date(),
            totalConnections: 0,
            activeConnections: 0,
            idleConnections: 0,
            waitingRequests: 0,
            errors: 0,
          },
          health: async () => true,
          dispose: async () => {},
        }),
        createPostgreSQL: async config => ({
          name: config.name,
          client: {},
          metrics: {
            created: new Date(),
            totalConnections: 0,
            activeConnections: 0,
            idleConnections: 0,
            waitingRequests: 0,
            errors: 0,
          },
          health: async () => true,
          dispose: async () => {},
        }),
        createCache: async config => ({
          name: config.name,
          client: {},
          metrics: {
            created: new Date(),
            totalConnections: 0,
            activeConnections: 0,
            idleConnections: 0,
            waitingRequests: 0,
            errors: 0,
          },
          health: async () => true,
          dispose: async () => {},
        }),
        createQueue: async config => ({
          name: config.name,
          client: {},
          metrics: {
            created: new Date(),
            totalConnections: 0,
            activeConnections: 0,
            idleConnections: 0,
            waitingRequests: 0,
            errors: 0,
          },
          health: async () => true,
          dispose: async () => {},
        }),
        getPool: (type, name) => undefined,
        listPools: () => [],
        disposeAll: async () => {},
      };

      expect(mockFactory.createMongoDB).toBeDefined();
      expect(mockFactory.createPostgreSQL).toBeDefined();
      expect(mockFactory.createCache).toBeDefined();
      expect(mockFactory.createQueue).toBeDefined();
      expect(mockFactory.getPool).toBeDefined();
      expect(mockFactory.listPools).toBeDefined();
      expect(mockFactory.disposeAll).toBeDefined();
    });
  });
});
