import type { SocketConfig, CacheConfig } from "@raclettejs/core"

type RacletteBackendConfig = {
  // not sure what we do here as this gets generated during runtime
  // mäh
  sockets?: {
    autoSend?: any
  }
  accessRateLimit?: {
    max: number
    timeWindow: string
  }
  cache?: {
    persistence?: string
  }
  onlyAllowLoginWithAdminTag?: true
  plugins?: string[]
  global?: {
    requireAuthentication?: boolean
    authTokenExpiryDays?: number
  }
  additionalPluginPaths?: string[]
}

// Cache for configuration
let cachedConfig: RacletteBackendConfig | null = null

type socketDefaultAutoSend =
  | "compositions"
  | "interactionLinks"
  | "projectConfig"

export class ConfigService {
  private config: RacletteBackendConfig | null = null

  constructor() {
    this.config = {}
  }

  async init() {
    await this.refreshConfig()

    return this
  }

  // Refresh the config (useful for hot reloading)
  public async refreshConfig(): Promise<void> {
    try {
      // Dynamic import for ESM - this allows for hot reloading
      const configModule = await import("../../../raclette.config.js")
      // const configModule = await import(
      //   process.env.NODE_ENV === "production"
      //     ? "../../../raclette.config.js"
      //     : "../../../raclette.config.ts=" + Date.now()
      // )

      this.config = configModule.racletteConfig

      cachedConfig = this.config
    } catch (error) {
      console.warn(
        `Error loading config: ${error instanceof Error ? error.message : String(error)}`,
      )
      // Keep using cached config if it exists
      this.config = cachedConfig
    }
  }

  // Get the entire config
  public getConfig(): RacletteBackendConfig | null {
    if (!this.config) {
      if (!cachedConfig) {
        console.error("Failed to load racletteJS configuration")
      }
      this.config = cachedConfig
    }

    return this.config
  }
  // Get cache configuration with defaults
  public getCacheConfig(): CacheConfig | {} {
    const config = this.getConfig()

    return config?.cache ?? {}
  }
  // Get cache persistence configuration
  public getCachePersistenceConfig(): CacheConfig["persistence"] | string {
    const cacheConfig = this.getCacheConfig()

    return cacheConfig?.persistence ?? "none"
  }
  // Get cache rdb configuration
  public getCacheRDBConfig(): CacheConfig["RDB_OPTIONS"] {
    const cacheConfig = this.getCacheConfig()

    return cacheConfig?.RDB_OPTIONS ?? "3600 1 300 100 60 10000"
  }
  // Get socket configuration with defaults
  public getSocketConfig(): SocketConfig {
    const config = this.getConfig()

    return config?.sockets ?? {}
  }

  // Get socket auto-send configuration
  public getSocketAutoSendConfig(): SocketConfig["autoSend"] | {} {
    const socketConfig = this.getSocketConfig()

    return socketConfig?.autoSend ?? {}
  }

  // Get socket security configuration
  public getSocketSecurityConfig(): SocketConfig["security"] {
    const socketConfig = this.getSocketConfig()

    return socketConfig.security || {}
  }

  // Get socket options configuration
  public getSocketOptionsConfig(): SocketConfig["options"] {
    const socketConfig = this.getSocketConfig()

    return socketConfig.options || {}
  }
  // get fastify rate limiter config
  public getFastifyRateLimits() {
    const config = this.getConfig()

    return config?.accessRateLimit ?? { max: 1000, timeWindow: 60000 }
  }
  // Helper to check if a specific auto-send feature is enabled
  // Default to true unless explicitly set to false
  public isAutoSendEnabled(feature: socketDefaultAutoSend): boolean {
    const autoSend = this.getSocketAutoSendConfig()

    return autoSend[feature] !== false
  }
  // Helper to check if auth is required
  // Default to true unless explicitly set to false
  public isAuthRequired(): boolean {
    return this.config?.global?.requireAuthentication ?? true
  }
  public getAuthTokenExpiryDays(): number {
    return this.config?.global?.authTokenExpiryDays ?? 30
  }
  public isAdminTagRequired(): boolean {
    return this.config?.onlyAllowLoginWithAdminTag ?? false
  }
  public getCustomSocketData(): Record<string, any> | undefined {
    const socketConfig = this.getSocketConfig()

    return socketConfig?.autoSend?.customData
  }

  public getPlugins(): string[] {
    return this.config?.plugins || []
  }

  public getAdditonalPluginPaths(): string[] {
    return this.config?.additionalPluginPaths || []
  }
}

// Create singleton instance
const configService = new ConfigService()

export default configService
