import { ToolingError } from '../../../../../../types'
import { withRetry, createHttpError, DEFAULT_RETRY_POLICY } from '../../../../../../../../../platform/resilience'
import type { ExecutionContext } from '../../../../../../../base/types'
import type { StartActorParams, StartActorResult } from '../../../../../../integration/types/apify'

interface ApifyCredentials {
  apiToken: string
}

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

/**
 * Start an Apify actor run and return immediately (no polling).
 *
 * Use this for long-running actors where results are delivered via webhook.
 * The actor runs on Apify's infrastructure independently.
 */
export async function startActor(
  credentials: ApifyCredentials,
  params: StartActorParams,
  context?: ExecutionContext
): Promise<StartActorResult> {
  const { apiToken } = credentials
  const { actorId, input = {}, webhooks, timeoutSecs, maxItems } = params

  if (!actorId) {
    throw new ToolingError('validation_error', 'Missing required parameter: actorId', {
      integration: 'apify',
      method: 'startActor'
    })
  }

  const encodedActorId = encodeURIComponent(actorId)
  const runUrl = `${APIFY_API_BASE}/acts/${encodedActorId}/runs`

  // Build request body -- Apify accepts webhooks as a JSON-encoded query param
  // or in the request body depending on API version. Use query param for webhooks.
  const url = webhooks ? `${runUrl}?webhooks=${encodeURIComponent(btoa(JSON.stringify(webhooks)))}` : runUrl

  const body: Record<string, unknown> = { ...input }
  if (timeoutSecs) body.timeout = timeoutSecs
  if (maxItems) body.maxItems = maxItems

  const runResponse = await withRetry(async () => {
    const response = await fetch(url, {
      method: 'POST',
      headers: {
        Authorization: `Bearer ${apiToken}`,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify(body)
    })

    if (!response.ok) {
      throw await createHttpError(response, {
        integration: 'apify',
        method: 'startActor',
        actorId
      })
    }

    return response.json()
  }, DEFAULT_RETRY_POLICY)

  const runId = runResponse.data?.id
  const defaultDatasetId = runResponse.data?.defaultDatasetId

  if (!runId) {
    throw new ToolingError('api_error', 'No run ID returned from Apify', {
      integration: 'apify',
      method: 'startActor',
      actorId
    })
  }

  if (context?.logger) {
    context.logger.info(
      `[ApifyAdapter] Actor started (async): organizationId=${context.organizationId} executionId=${context.executionId} actorId=${actorId} runId=${runId}`
    )
  }

  return {
    status: 'STARTED',
    runId,
    datasetId: defaultDatasetId || ''
  }
}
