import { computed, ref, type Ref } from 'vue'

import {
  fetchTencentBrowserSession,
  fetchTencentBrowserSessionSummary,
} from '@/services/tencent/session'
import type {
  TencentBrowserSessionData,
  TencentBrowserSessionStatus,
  TencentBrowserSessionSummaryData,
} from '@/types/tencent/session'

import { resolveTencentActionMessage } from './session-errors'

const POLL_INTERVAL_MS = 2_500
const POLL_FAILURE_LIMIT = 3

export const ACTIVE_TENCENT_SESSION_STATUSES = new Set([
  'waiting_scan',
  'scanned',
  'logged_in',
  'ready_to_redeem',
  'redeeming',
])

export function useTencentBrowserSessionPolling(options: {
  session: Ref<TencentBrowserSessionData | null>
  sessionLoading: Ref<boolean>
  notifyActionError: (error: unknown, fallbackMessage: string) => void
}) {
  const { session, sessionLoading, notifyActionError } = options
  const pollFailureCount = ref(0)
  const pollWarningMessage = ref('')

  let pollTimer: ReturnType<typeof setTimeout> | null = null
  let pollToken = 0

  const sessionNotice = computed(() => pollWarningMessage.value || session.value?.notice || '')

  async function refreshSession({ silent = false } = {}) {
    if (!session.value?.sessionId) {
      return false
    }

    if (!silent) {
      sessionLoading.value = true
      resetPollingWarning()
    }

    try {
      const currentSession = session.value
      const response = await fetchTencentBrowserSessionSummary(currentSession.sessionId)

      const nextSession = mergeSessionData(currentSession, response.data)
      session.value = nextSession

      if (shouldRefreshQrImage(currentSession, response.data)) {
        const fullResponse = await fetchTencentBrowserSession(currentSession.sessionId)

        session.value = mergeSessionData(nextSession, fullResponse.data)
      }

      if (silent) {
        resetPollingWarning()
      }

      return true
    } catch (error) {
      if (silent) {
        handleSilentPollingError(error)
      } else {
        notifyActionError(error, '获取浏览器会话状态失败')
      }

      return false
    } finally {
      if (!silent) {
        sessionLoading.value = false
      }
    }
  }

  function startPolling() {
    const token = ++pollToken

    const loop = async () => {
      if (token !== pollToken || !session.value?.sessionId) {
        return
      }

      await refreshSession({ silent: true })

      if (token !== pollToken || !isActiveTencentSessionStatus(session.value?.status)) {
        return
      }

      pollTimer = setTimeout(() => {
        void loop()
      }, POLL_INTERVAL_MS)
    }

    pollTimer = setTimeout(() => {
      void loop()
    }, POLL_INTERVAL_MS)
  }

  function resetPolling() {
    pollToken += 1

    if (pollTimer) {
      clearTimeout(pollTimer)
      pollTimer = null
    }
  }

  function resetPollingWarning() {
    pollFailureCount.value = 0
    pollWarningMessage.value = ''
  }

  function restartPollingIfActive(nextSession = session.value) {
    if (isActiveTencentSessionStatus(nextSession?.status)) {
      startPolling()
    }
  }

  function handleSilentPollingError(error: unknown) {
    console.error(error)
    pollFailureCount.value += 1

    if (pollFailureCount.value < POLL_FAILURE_LIMIT) {
      return
    }

    pollWarningMessage.value = `${resolveTencentActionMessage(
      error,
      '会话状态刷新失败',
    )}，已暂停自动轮询，请手动刷新或重新生成二维码。`
    resetPolling()
  }

  return {
    refreshSession,
    resetPolling,
    resetPollingWarning,
    restartPollingIfActive,
    sessionNotice,
    startPolling,
  }
}

export function isActiveTencentSessionStatus(
  status: TencentBrowserSessionStatus | null | undefined,
) {
  return Boolean(status && ACTIVE_TENCENT_SESSION_STATUSES.has(status))
}

function mergeSessionData(
  current: TencentBrowserSessionData | null,
  next: TencentBrowserSessionSummaryData | TencentBrowserSessionData,
) {
  if (!current) {
    return {
      ...next,
      qrImageBase64: next.qrImageBase64 || '',
    }
  }

  return {
    ...current,
    ...next,
    qrImageBase64:
      typeof next.qrImageBase64 === 'string' ? next.qrImageBase64 : current.qrImageBase64,
    activityInfo: next.activityInfo ?? current.activityInfo ?? null,
    redeem: next.redeem ?? current.redeem ?? null,
    artifacts: next.artifacts || current.artifacts,
  }
}

function shouldRefreshQrImage(
  current: TencentBrowserSessionData,
  next: TencentBrowserSessionSummaryData,
) {
  if (!next.artifacts?.hasQrImage) {
    return false
  }

  if (!current.qrImageBase64) {
    return true
  }

  return Boolean(next.qrUpdatedAt && next.qrUpdatedAt !== current.qrUpdatedAt)
}
