interface KeycloakClientOptions {
  timeout?: number
  retries?: number
  retryDelay?: number
}

interface CircuitBreakerState {
  failures: number
  lastFailure: number
  isOpen: boolean
}

// Simple connection pool and circuit breaker for Keycloak requests
class KeycloakClient {
  private static instance: KeycloakClient
  private circuitBreaker: CircuitBreakerState = {
    failures: 0,
    lastFailure: 0,
    isOpen: false
  }
  private readonly maxFailures = 5
  private readonly resetTimeout = 60000 // 1 minute

  private constructor() {}

  static getInstance(): KeycloakClient {
    if (!KeycloakClient.instance) {
      KeycloakClient.instance = new KeycloakClient()
    }
    return KeycloakClient.instance
  }

  private isCircuitOpen(): boolean {
    if (this.circuitBreaker.isOpen) {
      // Check if we should reset the circuit breaker
      if (Date.now() - this.circuitBreaker.lastFailure > this.resetTimeout) {
        console.log('[KEYCLOAK_CLIENT] Circuit breaker reset - attempting requests')
        this.circuitBreaker.isOpen = false
        this.circuitBreaker.failures = 0
      }
    }
    return this.circuitBreaker.isOpen
  }

  private recordFailure(): void {
    this.circuitBreaker.failures++
    this.circuitBreaker.lastFailure = Date.now()
    
    if (this.circuitBreaker.failures >= this.maxFailures) {
      console.error(`[KEYCLOAK_CLIENT] Circuit breaker OPEN - too many failures (${this.circuitBreaker.failures})`)
      this.circuitBreaker.isOpen = true
    }
  }

  private recordSuccess(): void {
    if (this.circuitBreaker.failures > 0) {
      console.log('[KEYCLOAK_CLIENT] Request successful - resetting failure count')
      this.circuitBreaker.failures = 0
    }
  }

  async fetch(url: string, options: any = {}, clientOptions: KeycloakClientOptions = {}): Promise<any> {
    const {
      retries = 3,
      retryDelay = 1000
    } = clientOptions

    // Check circuit breaker
    if (this.isCircuitOpen()) {
      throw createError({
        statusCode: 503,
        statusMessage: 'Keycloak service temporarily unavailable (circuit breaker open)'
      })
    }

    const startTime = Date.now()
    let lastError: any

    for (let attempt = 1; attempt <= retries + 1; attempt++) {
      try {
        console.log(`[KEYCLOAK_CLIENT] Attempt ${attempt}/${retries + 1} for ${url}`)

        // Use basic $fetch without problematic options
        const response = await $fetch(url, {
          ...options,
          // Don't add custom headers that might be incompatible
          retry: 0 // Disable automatic retries from $fetch to handle them ourselves
        })

        const duration = Date.now() - startTime
        console.log(`[KEYCLOAK_CLIENT] Request successful in ${duration}ms`)
        
        this.recordSuccess()
        return response

      } catch (error: any) {
        lastError = error
        const duration = Date.now() - startTime
        
        console.error(`[KEYCLOAK_CLIENT] Attempt ${attempt} failed after ${duration}ms:`, {
          status: error.status,
          message: error.message,
          url: url.replace(/client_secret=[^&]*/g, 'client_secret=***')
        })

        // Don't retry on client errors (4xx)
        if (error.status >= 400 && error.status < 500) {
          console.log('[KEYCLOAK_CLIENT] Client error - no retry')
          this.recordFailure()
          throw error
        }

        // Don't retry on the last attempt
        if (attempt === retries + 1) {
          console.error('[KEYCLOAK_CLIENT] All retry attempts exhausted')
          this.recordFailure()
          break
        }

        // Exponential backoff delay
        const delay = retryDelay * Math.pow(2, attempt - 1)
        console.log(`[KEYCLOAK_CLIENT] Waiting ${delay}ms before retry...`)
        await new Promise(resolve => setTimeout(resolve, delay))
      }
    }

    this.recordFailure()
    throw lastError || createError({
      statusCode: 502,
      statusMessage: 'Failed to connect to Keycloak after multiple attempts'
    })
  }

  async exchangeCodeForTokens(code: string, redirectUri: string): Promise<any> {
    const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET
    if (!clientSecret) {
      throw createError({
        statusCode: 500,
        statusMessage: 'KEYCLOAK_CLIENT_SECRET not configured'
      })
    }

    const tokenUrl = 'https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/token'
    
    return this.fetch(tokenUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        grant_type: 'authorization_code',
        client_id: 'client-portal',
        client_secret: clientSecret,
        code: code,
        redirect_uri: redirectUri
      }).toString()
    }, {
      timeout: 20000, // 20 second timeout for token exchange
      retries: 2 // Only 2 retries for auth operations
    })
  }

  async getUserInfo(accessToken: string): Promise<any> {
    const userInfoUrl = 'https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/userinfo'
    
    return this.fetch(userInfoUrl, {
      headers: {
        'Authorization': `Bearer ${accessToken}`
      }
    }, {
      timeout: 15000, // 15 second timeout for user info
      retries: 2
    })
  }

  async refreshAccessToken(refreshToken: string): Promise<any> {
    const clientSecret = process.env.KEYCLOAK_CLIENT_SECRET
    if (!clientSecret) {
      throw createError({
        statusCode: 500,
        statusMessage: 'KEYCLOAK_CLIENT_SECRET not configured'
      })
    }

    const tokenUrl = 'https://auth.portnimara.dev/realms/client-portal/protocol/openid-connect/token'
    
    return this.fetch(tokenUrl, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/x-www-form-urlencoded',
      },
      body: new URLSearchParams({
        grant_type: 'refresh_token',
        client_id: 'client-portal',
        client_secret: clientSecret,
        refresh_token: refreshToken
      }).toString()
    }, {
      timeout: 15000,
      retries: 1 // Only 1 retry for refresh operations
    })
  }

  getCircuitBreakerStatus() {
    return {
      isOpen: this.circuitBreaker.isOpen,
      failures: this.circuitBreaker.failures,
      lastFailure: this.circuitBreaker.lastFailure ? new Date(this.circuitBreaker.lastFailure).toISOString() : null
    }
  }
}

// Export singleton instance
export const keycloakClient = KeycloakClient.getInstance()

// Helper function for backward compatibility
export const keycloakFetch = (url: string, options: any = {}, clientOptions: KeycloakClientOptions = {}) => {
  return keycloakClient.fetch(url, options, clientOptions)
}
