import type { DIContainer, ServiceToken } from './types'

export type { ServiceToken } from './types'

interface ServiceRegistration {
  service: any
  scope: 'singleton' | 'transient'
  instance?: any
}

/**
 * Dependency Injection Container
 * Manages service registration and injection across modules
 */
export class DIContainerImpl implements DIContainer {
  private services = new Map<ServiceToken, ServiceRegistration>()

  /**
   * Register a service in the container
   */
  provide<T>(token: ServiceToken, service: T, scope: 'singleton' | 'transient' = 'singleton'): void {
    this.services.set(token, {
      service,
      scope,
      instance: scope === 'singleton' ? service : undefined
    })
  }

  /**
   * Inject a service from the container
   */
  inject<T>(token: ServiceToken): T | undefined {
    const registration = this.services.get(token)
    
    if (!registration) {
      return undefined
    }

    if (registration.scope === 'singleton') {
      return registration.instance as T
    }

    // For transient services, create new instance
    // Note: This assumes the service is a constructor function
    if (typeof registration.service === 'function') {
      try {
        return new registration.service() as T
      } catch (error) {
        console.error(`Error creating transient service for token ${String(token)}:`, error)
        return undefined
      }
    }

    return registration.service as T
  }

  /**
   * Remove a service from the container
   */
  remove(token: ServiceToken): boolean {
    return this.services.delete(token)
  }

  /**
   * Clear all services
   */
  clear(): void {
    this.services.clear()
  }

  /**
   * Get all registered service tokens
   */
  getRegisteredTokens(): ServiceToken[] {
    return Array.from(this.services.keys())
  }

  /**
   * Check if a service is registered
   */
  has(token: ServiceToken): boolean {
    return this.services.has(token)
  }

  /**
   * Get service registration info
   */
  getServiceInfo(token: ServiceToken): { scope: string; hasInstance: boolean } | undefined {
    const registration = this.services.get(token)
    if (!registration) {
      return undefined
    }

    return {
      scope: registration.scope,
      hasInstance: registration.instance !== undefined
    }
  }
}

// Global DI container instance
export const container = new DIContainerImpl()

// Service token constants
export const SERVICE_TOKENS = {
  // Core services
  EVENT_BUS: Symbol('eventBus'),
  ROUTER: Symbol('router'),
  
  // Nostr services  
  RELAY_HUB: Symbol('relayHub'),
  
  // Auth services
  AUTH_SERVICE: Symbol('authService'),
  
  // Payment services
  PAYMENT_SERVICE: Symbol('paymentService'),
  
  // Visibility services
  VISIBILITY_SERVICE: Symbol('visibilityService'),
  
  // Storage services
  STORAGE_SERVICE: Symbol('storageService'),
  
  // Toast services
  TOAST_SERVICE: Symbol('toastService'),
  
  // Market services
  MARKET_STORE: Symbol('marketStore'),
  PAYMENT_MONITOR: Symbol('paymentMonitor'),
  
  // Chat services
  CHAT_SERVICE: Symbol('chatService'),

  // Feed services
  FEED_SERVICE: Symbol('feedService'),
  PROFILE_SERVICE: Symbol('profileService'),
  REACTION_SERVICE: Symbol('reactionService'),

  // Events services
  EVENTS_SERVICE: Symbol('eventsService'),
  
  // Invoice services
  INVOICE_SERVICE: Symbol('invoiceService'),
  
  // Nostrmarket services
  NOSTRMARKET_SERVICE: Symbol('nostrmarketService'),
  NOSTRMARKET_API: Symbol('nostrmarketAPI'),
  
  // Wallet services
  WALLET_SERVICE: Symbol('walletService'),
  WALLET_WEBSOCKET_SERVICE: Symbol('walletWebSocketService'),
  
  // API services
  LNBITS_API: Symbol('lnbitsAPI'),
} as const

// Type-safe injection helpers
export function injectService<T>(token: ServiceToken): T {
  const service = container.inject<T>(token)
  if (!service) {
    throw new Error(`Service not found for token: ${String(token)}`)
  }
  return service
}

export function tryInjectService<T>(token: ServiceToken): T | undefined {
  return container.inject<T>(token)
}