/**
 * Dependency Injection Container
 * 
 * Enterprise DI using tsyringe for:
 * - Service decoupling
 * - Testability
 * - Lifecycle management
 */

import 'reflect-metadata';
import { container } from 'tsyringe';
import { PrismaClient } from '@prisma/client';
import { logger } from '@/shared/utils/logger';

// ============================================
// Token Registrations
// ============================================

export const TOKENS = {
  // Infrastructure
  PrismaClient: Symbol.for('PrismaClient'),
  RedisClient: Symbol.for('RedisClient'),
  Logger: Symbol.for('Logger'),
  
  // Repositories
  UserRepository: Symbol.for('UserRepository'),
  ExerciseRepository: Symbol.for('ExerciseRepository'),
  ModuleRepository: Symbol.for('ModuleRepository'),
  ProgressRepository: Symbol.for('ProgressRepository'),
  RankingRepository: Symbol.for('RankingRepository'),
  NotificationRepository: Symbol.for('NotificationRepository'),
  
  // Services
  AuthService: Symbol.for('AuthService'),
  UserService: Symbol.for('UserService'),
  ExerciseService: Symbol.for('ExerciseService'),
  ModuleService: Symbol.for('ModuleService'),
  ProgressService: Symbol.for('ProgressService'),
  RankingService: Symbol.for('RankingService'),
  NotificationService: Symbol.for('NotificationService'),
  CacheService: Symbol.for('CacheService'),
} as const;

// ============================================
// Container Configuration
// ============================================

/**
 * Configure the DI container
 * Call this before using the container
 */
export function configureContainer(prisma: PrismaClient): void {
  // Register Prisma Client
  container.register(TOKENS.PrismaClient, {
    useValue: prisma,
  });
  
  // Register Logger
  container.register(TOKENS.Logger, {
    useValue: logger,
  });
  
  // Services are registered as singletons by default
  // Repositories can be registered as transient if needed
}

/**
 * Resolve a dependency from the container
 */
export function resolve<T>(token: symbol): T {
  return container.resolve<T>(token);
}

/**
 * Get the configured container instance
 */
export { container };

export default container;
