import { runtimeConfig } from '../../config/runtime.js'
import { logDebug } from '../../utils/logger.js'

const SESSION_DEBUG_ENABLED = Boolean(runtimeConfig.session.debug)

type FrameLike = unknown

type PageWithFrames = {
  frames: () => FrameLike[]
  waitForTimeout: (milliseconds: number) => Promise<void>
}

type QrDownloadResponse = {
  ok: () => boolean
  status: () => number
  body: () => Promise<Buffer>
}

type PageWithRequestContext = {
  context: () => {
    request: {
      get: (url: string, options?: {
        failOnStatusCode?: boolean
        headers?: Record<string, string>
      }) => Promise<QrDownloadResponse>
    }
  }
}

export function logBrowserSessionDebug(scope: string, detail?: unknown): void {
  if (!SESSION_DEBUG_ENABLED) {
    return
  }

  logDebug('[browser/session]', scope, detail)
}

export async function waitForFrame<TFrame extends FrameLike>(
  page: PageWithFrames,
  predicate: (frame: TFrame) => boolean,
  timeoutMs = 15_000,
): Promise<TFrame> {
  const startedAt = Date.now()

  while (Date.now() - startedAt < timeoutMs) {
    const matched = page.frames().find((frame): frame is TFrame => {
      try {
        return predicate(frame as TFrame)
      } catch {
        return false
      }
    })

    if (matched) {
      return matched
    }

    await page.waitForTimeout(300)
  }

  throw new Error('未找到登录二维码 frame')
}

export async function downloadRemoteQrImage(
  page: PageWithRequestContext,
  qrUrl: string,
  qrImagePath: string,
  referer = '',
  loginType = 'unknown',
): Promise<Buffer | false | null> {
  try {
    const response = await page.context().request.get(qrUrl, {
      failOnStatusCode: false,
      headers: {
        referer,
      },
    })

    if (!response.ok()) {
      logBrowserSessionDebug(`${loginType}.capture.downloadNotOk`, {
        qrUrl,
        status: response.status(),
      })
      return false
    }

    const body = await response.body()

    if (!body?.length) {
      return false
    }

    return body
  } catch (error) {
    logBrowserSessionDebug(`${loginType}.capture.downloadError`, {
      qrUrl,
      message: error instanceof Error ? error.message : String(error),
    })
    return null
  }
}

export function isRetryableQrCaptureError(error: unknown): boolean {
  const message = error instanceof Error ? error.message : String(error || '')

  return (
    message.includes('Frame was detached') ||
    message.includes('Execution context was destroyed') ||
    message.includes('Target page, context or browser has been closed') ||
    message.includes('waiting for') ||
    message.includes('Timeout')
  )
}
