interface SuperTokensCoreHealthProbeOptions {
  connectionUri: string
  apiDomain: string
  websiteDomain: string
  timeoutMs?: number
  fetchImpl?: typeof fetch
}

export interface SuperTokensCoreHealthSnapshot {
  configured: boolean
  reachable: boolean
  ready: boolean
  apiVersion: string | null
  error: string | null
}

function normalizeTrimmed(value: string) {
  return value.trim()
}

function parseApiVersions(payload: unknown): string[] {
  if (!payload || typeof payload !== 'object') {
    return []
  }

  const rawVersions = (payload as { versions?: unknown }).versions
  if (!Array.isArray(rawVersions)) {
    return []
  }

  return rawVersions
    .map((value) => String(value || '').trim())
    .filter(Boolean)
}

function compareVersionNumbers(left: string, right: string) {
  const leftParts = left.split('.').map((part) => Number(part))
  const rightParts = right.split('.').map((part) => Number(part))
  const maxLength = Math.max(leftParts.length, rightParts.length)

  for (let index = 0; index < maxLength; index += 1) {
    const leftValue = Number.isFinite(leftParts[index]) ? leftParts[index] : 0
    const rightValue = Number.isFinite(rightParts[index]) ? rightParts[index] : 0
    if (leftValue > rightValue) return 1
    if (leftValue < rightValue) return -1
  }

  return 0
}

function pickHighestVersion(versions: string[]) {
  if (versions.length === 0) {
    return null
  }

  return versions.reduce((highest, candidate) => (
    compareVersionNumbers(candidate, highest) > 0 ? candidate : highest
  ))
}

export function buildSuperTokensApiVersionUrl({
  connectionUri,
  apiDomain,
  websiteDomain,
}: Pick<SuperTokensCoreHealthProbeOptions, 'connectionUri' | 'apiDomain' | 'websiteDomain'>) {
  const url = new URL(normalizeTrimmed(connectionUri))
  const nextPath = `${url.pathname.replace(/\/+$/, '')}/apiversion`.replace(/\/{2,}/g, '/')
  url.pathname = nextPath.startsWith('/') ? nextPath : `/${nextPath}`
  url.search = ''
  url.searchParams.set('apiDomain', normalizeTrimmed(apiDomain))
  url.searchParams.set('websiteDomain', normalizeTrimmed(websiteDomain))
  return url.toString()
}

export async function probeSuperTokensCoreHealth({
  connectionUri,
  apiDomain,
  websiteDomain,
  timeoutMs = 2_000,
  fetchImpl = fetch,
}: SuperTokensCoreHealthProbeOptions): Promise<SuperTokensCoreHealthSnapshot> {
  const normalizedConnectionUri = normalizeTrimmed(connectionUri)
  const normalizedApiDomain = normalizeTrimmed(apiDomain)
  const normalizedWebsiteDomain = normalizeTrimmed(websiteDomain)
  const configured = Boolean(normalizedConnectionUri && normalizedApiDomain && normalizedWebsiteDomain)

  if (!configured) {
    return {
      configured: false,
      reachable: false,
      ready: false,
      apiVersion: null,
      error: 'not_configured',
    }
  }

  const controller = new AbortController()
  const timeout = setTimeout(() => controller.abort(), Math.max(250, timeoutMs))
  timeout.unref?.()

  try {
    const response = await fetchImpl(
      buildSuperTokensApiVersionUrl({
        connectionUri: normalizedConnectionUri,
        apiDomain: normalizedApiDomain,
        websiteDomain: normalizedWebsiteDomain,
      }),
      {
        method: 'GET',
        headers: {
          accept: 'application/json',
        },
        signal: controller.signal,
      },
    )

    if (!response.ok) {
      return {
        configured: true,
        reachable: false,
        ready: false,
        apiVersion: null,
        error: `http_${response.status}`,
      }
    }

    const versions = parseApiVersions(await response.json())
    const apiVersion = pickHighestVersion(versions)
    if (!apiVersion) {
      return {
        configured: true,
        reachable: false,
        ready: false,
        apiVersion: null,
        error: 'invalid_payload',
      }
    }

    return {
      configured: true,
      reachable: true,
      ready: true,
      apiVersion,
      error: null,
    }
  } catch (error) {
    return {
      configured: true,
      reachable: false,
      ready: false,
      apiVersion: null,
      error: error instanceof Error && error.name === 'AbortError' ? 'timeout' : 'unreachable',
    }
  } finally {
    clearTimeout(timeout)
  }
}
