import type { BaseIntegrationAdapter } from '../../../base-integration-adapter'
import { ToolingError } from '../../../../types'
import type { ExecutionContext } from '../../../../../base/types'
import { runActor } from './fetch/run-actor/index'
import { getDatasetItems } from './fetch/get-dataset-items/index'
import { startActor } from './fetch/start-actor/index'
import type { StartActorParams } from '../../../../integration/types/apify'
import { createHttpError, withRetry, DEFAULT_RETRY_POLICY } from '../../../../../../../platform/resilience'

interface ApifyCredentials {
  apiToken?: string
  apiKey?: string
  api_token?: string
  token?: string
}

export interface ApifyVerifyResult {
  ok: true
  provider: 'apify'
  username?: string
  plan?: string
}

type ApifyPlan =
  | string
  | {
      id?: string
      name?: string
      description?: string
    }

interface ApifyUserResponse {
  data?: {
    username?: string
    plan?: ApifyPlan
    id?: string
  }
}

interface RunActorParams {
  actorId: string
  input?: Record<string, unknown>
  timeoutSecs?: number
  pollIntervalSecs?: number
  maxItems?: number
}

interface GetDatasetItemsParams {
  datasetId: string
  maxItems?: number
  offset?: number
}

const APIFY_API_BASE_URL = 'https://api.apify.com/v2'

/**
 * Apify integration adapter
 *
 * Provides access to Apify actor automation platform for web scraping
 * and browser automation tasks.
 *
 * @example
 * const adapter = new ApifyAdapter()
 * const result = await adapter.call(
 *   'runActor',
 *   { actorId: 'curious_coder/clutch-scraper', input: { category: 'digital-marketing' } },
 *   { apiToken: 'apify_api_...' },
 *   context
 * )
 */
export class ApifyAdapter implements BaseIntegrationAdapter {
  readonly name = 'apify'

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

    // Normalize credentials to consistent field name
    const normalizedCreds = this.normalizeCredentials(credentials as unknown as ApifyCredentials)

    // Route to method handler
    switch (method) {
      case 'verify':
        return this.verify(normalizedCreds, context)
      case 'runActor':
        return runActor(normalizedCreds, params as RunActorParams, context)
      case 'getDatasetItems':
        return getDatasetItems(normalizedCreds, params as GetDatasetItemsParams, context)
      case 'startActor':
        return startActor(normalizedCreds, params as StartActorParams, context)
      default:
        throw new ToolingError('method_not_found', `Unknown Apify method: ${method}`, {
          integration: this.name,
          method,
          organizationId: context?.organizationId
        })
    }
  }

  validateCredentials(credentials: Record<string, unknown>): boolean {
    const creds = credentials as unknown as ApifyCredentials
    const token = creds.apiToken || creds.apiKey || creds.api_token || creds.token
    return typeof token === 'string' && token.trim().length > 0
  }

  async verify(credentials: ApifyCredentials, context?: ExecutionContext): Promise<ApifyVerifyResult> {
    const normalizedCreds = this.normalizeCredentials(credentials)
    const response = await withRetry(async () => {
      const result = await fetch(`${APIFY_API_BASE_URL}/users/me`, {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${normalizedCreds.apiToken}`,
          'Content-Type': 'application/json'
        }
      })

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

      return result
    }, DEFAULT_RETRY_POLICY)

    const data = (await response.json()) as ApifyUserResponse

    return {
      ok: true,
      provider: 'apify',
      username: data.data?.username ?? data.data?.id,
      plan: formatApifyPlan(data.data?.plan)
    }
  }

  /**
   * Normalize credentials to use consistent field name
   */
  private normalizeCredentials(credentials: ApifyCredentials): { apiToken: string } {
    const token = credentials.apiToken || credentials.apiKey || credentials.api_token || credentials.token
    if (!token) {
      throw new ToolingError('credentials_invalid', 'Missing Apify API token', {
        integration: this.name
      })
    }
    return { apiToken: token.trim() }
  }
}

function formatApifyPlan(plan: ApifyPlan | undefined): string | undefined {
  if (!plan) return undefined
  if (typeof plan === 'string') return plan
  return plan.id ?? plan.name ?? plan.description
}
