import type { BaseIntegrationAdapter } from '../../../base-integration-adapter'
import { ToolingError } from '../../../../types'
import type { ExecutionContext } from '../../../../../base/types'
import { createHttpError, withRetry, DEFAULT_RETRY_POLICY } from '../../../../../../../platform/resilience'

export interface ApolloCredentials {
  apiKey?: string
  apolloApiKey?: string
  APOLLO_API_KEY?: string
  key?: string
  token?: string
}

export interface ApolloVerifyResult {
  ok: true
  provider: 'apollo'
  authenticated: boolean
}

const APOLLO_AUTH_HEALTH_URL = 'https://api.apollo.io/v1/auth/health'

export class ApolloAdapter implements BaseIntegrationAdapter {
  readonly name = 'apollo'

  async call(
    method: string,
    params: unknown,
    credentials: Record<string, unknown>,
    context?: ExecutionContext
  ): Promise<unknown> {
    if (!this.validateCredentials(credentials)) {
      throw new ToolingError('credentials_invalid', 'Invalid Apollo credentials', {
        integration: this.name,
        organizationId: context?.organizationId
      })
    }

    switch (method) {
      case 'verify':
        return this.verify(credentials as unknown as ApolloCredentials, context)
      default:
        throw new ToolingError('method_not_found', `Unknown Apollo method: ${method}`, {
          integration: this.name,
          method,
          organizationId: context?.organizationId
        })
    }
  }

  validateCredentials(credentials: Record<string, unknown>): boolean {
    const token = this.getToken(credentials as unknown as ApolloCredentials)
    return typeof token === 'string' && token.trim().length > 0
  }

  async verify(credentials: ApolloCredentials, context?: ExecutionContext): Promise<ApolloVerifyResult> {
    const token = this.normalizeCredentials(credentials).apiKey
    await withRetry(async () => {
      const response = await fetch(APOLLO_AUTH_HEALTH_URL, {
        method: 'GET',
        headers: {
          accept: 'application/json',
          'x-api-key': token,
          authorization: `Bearer ${token}`
        }
      })

      if (!response.ok) {
        throw await createHttpError(response, {
          integration: this.name,
          method: 'verify',
          organizationId: context?.organizationId
        })
      }

      return response
    }, DEFAULT_RETRY_POLICY)

    return {
      ok: true,
      provider: 'apollo',
      authenticated: true
    }
  }

  private normalizeCredentials(credentials: ApolloCredentials): { apiKey: string } {
    const token = this.getToken(credentials)
    if (!token) {
      throw new ToolingError('credentials_invalid', 'Missing Apollo API key', {
        integration: this.name
      })
    }

    return { apiKey: token.trim() }
  }

  private getToken(credentials: ApolloCredentials): string | undefined {
    return credentials.apiKey ?? credentials.apolloApiKey ?? credentials.APOLLO_API_KEY ?? credentials.key ?? credentials.token
  }
}
