/**
 * Test DI library functionality
 */
import { describe, expect, test } from 'bun:test';
import {
  ConnectionFactory,
  OperationContext,
  PoolSizeCalculator,
  ServiceContainer,
} from '../src/index';

describe('DI Library', () => {
  test('ServiceContainer - sync resolution', () => {
    const container = new ServiceContainer('test');

    container.register({
      name: 'testService',
      factory: () => ({ value: 'test' }),
      singleton: true,
    });

    const service = container.resolve<{ value: string }>('testService');
    expect(service.value).toBe('test');
  });

  test('ServiceContainer - async resolution', async () => {
    const container = new ServiceContainer('test');

    container.register({
      name: 'asyncService',
      factory: async () => ({ value: 'async-test' }),
      singleton: true,
    });

    const service = await container.resolveAsync<{ value: string }>('asyncService');
    expect(service.value).toBe('async-test');
  });

  test('ServiceContainer - scoped container', () => {
    const container = new ServiceContainer('test');

    container.register({
      name: 'testService',
      factory: () => ({ value: 'test' }),
      singleton: true,
    });

    const scopedContainer = container.createScope();
    const service = scopedContainer.resolve<{ value: string }>('testService');
    expect(service.value).toBe('test');
  });

  test('ServiceContainer - error on unregistered service', () => {
    const container = new ServiceContainer('test');

    expect(() => {
      container.resolve('nonexistent');
    }).toThrow('Service nonexistent not registered');
  });

  test('ServiceContainer - async service throws error on sync resolve', () => {
    const container = new ServiceContainer('test');

    container.register({
      name: 'asyncService',
      factory: async () => ({ value: 'async' }),
      singleton: true,
    });

    expect(() => {
      container.resolve('asyncService');
    }).toThrow('Service asyncService is async. Use resolveAsync() instead.');
  });

  test('ServiceContainer - disposal', async () => {
    const container = new ServiceContainer('test');
    let disposed = false;

    container.register({
      name: 'disposableService',
      factory: () => ({ value: 'test' }),
      singleton: true,
      dispose: async () => {
        disposed = true;
      },
    });

    // Create instance
    container.resolve('disposableService');

    // Dispose container
    await container.dispose();
    expect(disposed).toBe(true);
  });

  test('OperationContext - enhanced functionality', () => {
    const container = new ServiceContainer('test');
    const context = OperationContext.create('test-handler', 'test-operation', {
      container,
      metadata: { userId: '123' },
    });

    expect(context).toBeDefined();
    expect(context.logger).toBeDefined();
    expect(context.traceId).toBeDefined();
    expect(context.metadata.userId).toBe('123');
    expect(context.getExecutionTime()).toBeGreaterThanOrEqual(0);
  });

  test('OperationContext - service resolution', () => {
    const container = new ServiceContainer('test');

    container.register({
      name: 'testService',
      factory: () => ({ value: 'resolved' }),
      singleton: true,
    });

    const context = OperationContext.create('test-handler', 'test-operation', {
      container,
    });

    const service = context.resolve<{ value: string }>('testService');
    expect(service.value).toBe('resolved');
  });

  test('ConnectionFactory - creation', () => {
    const factory = new ConnectionFactory({
      service: 'test',
      environment: 'development',
    });

    expect(factory).toBeDefined();
    expect(factory.listPools()).toEqual([]);
  });

  test('OperationContext - creation', () => {
    const container = new ServiceContainer('test');
    const context = OperationContext.create('test-handler', 'test-operation', {
      container,
    });

    expect(context).toBeDefined();
    expect(context.logger).toBeDefined();
  });

  test('OperationContext - child context', () => {
    const context = OperationContext.create('test-handler', 'test-operation');
    const child = context.createChild('child-operation');

    expect(child).toBeDefined();
    expect(child.logger).toBeDefined();
  });

  test('PoolSizeCalculator - service defaults', () => {
    const poolSize = PoolSizeCalculator.calculate('data-ingestion');
    expect(poolSize).toEqual({ min: 5, max: 50, idle: 10 });
  });

  test('PoolSizeCalculator - handler defaults', () => {
    const poolSize = PoolSizeCalculator.calculate('unknown-service', 'batch-import');
    expect(poolSize).toEqual({ min: 10, max: 100, idle: 20 });
  });

  test('PoolSizeCalculator - fallback defaults', () => {
    const poolSize = PoolSizeCalculator.calculate('unknown-service', 'unknown-handler');
    expect(poolSize).toEqual({ min: 2, max: 10, idle: 3 });
  });

  test('PoolSizeCalculator - custom config', () => {
    const poolSize = PoolSizeCalculator.calculate('test-service', undefined, {
      minConnections: 5,
      maxConnections: 15,
    });
    expect(poolSize).toEqual({ min: 5, max: 15, idle: 5 });
  });

  test('PoolSizeCalculator - optimal size calculation', () => {
    const optimalSize = PoolSizeCalculator.getOptimalPoolSize(10, 100, 50);
    expect(optimalSize).toBeGreaterThan(0);
    expect(typeof optimalSize).toBe('number');
  });
});
