import React, { useEffect, useMemo, useRef } from 'react'

import { Center, Loader } from '@mantine/core'
import { Navigate, useLocation } from 'react-router-dom'

import { ngmContextFromCluster } from '~/api/ngm'
import { useCurCluster, useCurOrg, useUserStore } from '~/hooks/state'
import {
  isStatementV2Eligible,
  useStatementsDatasource
} from '~/hooks/use-statement-datasource'
import { clusterDetailTelemetry } from '~/telemetry'
import {
  StatementRouteResolution,
  buildClinicStatementPath,
  buildStatementV1DashboardUrl,
  resolveStatementRoute
} from '~/utils/statement-routing'

const StatementRouteLoading: React.FC = () => (
  <Center style={{ minHeight: 'calc(100vh - 48px)' }}>
    <Loader variant='bars' size='md' />
  </Center>
)

function useStatementRouteResolution() {
  const { curOrg } = useCurOrg()
  const { curCluster } = useCurCluster()
  const internal = !!useUserStore((state) => state.user?.internal)
  const eligible = isStatementV2Eligible(curCluster)
  const ngmContext = useMemo(
    () =>
      curCluster && curOrg
        ? ngmContextFromCluster(curCluster, curOrg.externalID || '')
        : null,
    [curCluster, curOrg]
  )
  const datasourceQuery = useStatementsDatasource(
    ngmContext,
    internal && eligible
  )
  const resolution = resolveStatementRoute({
    internal,
    eligible,
    probeLoading: datasourceQuery.isLoading && !datasourceQuery.data,
    probeError: datasourceQuery.isError,
    v2Available: datasourceQuery.data?.v2_available
  })

  return { curCluster, curOrg, resolution }
}

function useTrackStatementRouteResolution(
  source: 'resolver' | 'direct-v2',
  resolution: StatementRouteResolution
) {
  const lastEvent = useRef('')

  useEffect(() => {
    if (resolution.decision === 'pending') return
    const eventKey = `${source}:${resolution.decision}:${resolution.reason}`
    if (lastEvent.current === eventKey) return
    lastEvent.current = eventKey
    clusterDetailTelemetry.resolveSQLStatementRoute(
      source,
      resolution.decision,
      resolution.reason
    )
  }, [resolution, source])
}

function clusterRootPath(orgId: string, clusterId: string) {
  return `/orgs/${orgId}/clusters/${clusterId}`
}

export const StatementVersionResolver: React.FC = () => {
  const location = useLocation()
  const { curCluster, curOrg, resolution } = useStatementRouteResolution()
  useTrackStatementRouteResolution('resolver', resolution)

  if (!curCluster || !curOrg || resolution.decision === 'pending') {
    return <StatementRouteLoading />
  }
  if (resolution.decision === 'denied') {
    return (
      <Navigate
        replace
        to={clusterRootPath(curOrg.id || '', curCluster.id || '')}
      />
    )
  }
  if (resolution.decision === 'v2') {
    return (
      <Navigate
        replace
        to={buildClinicStatementPath(
          curOrg.id || '',
          curCluster.id || '',
          'v2',
          location.search
        )}
      />
    )
  }

  return (
    <StatementV1DashboardRedirect
      url={buildStatementV1DashboardUrl(curCluster, curOrg, location.search)}
    />
  )
}

const StatementV1DashboardRedirect: React.FC<{ url: string }> = ({ url }) => {
  useEffect(() => {
    window.location.replace(url)
  }, [url])

  return <StatementRouteLoading />
}

export const StatementV2RouteGuard: React.FC<React.PropsWithChildren> = ({
  children
}) => {
  const location = useLocation()
  const { curCluster, curOrg, resolution } = useStatementRouteResolution()
  useTrackStatementRouteResolution('direct-v2', resolution)

  if (!curCluster || !curOrg || resolution.decision === 'pending') {
    return <StatementRouteLoading />
  }
  if (resolution.decision === 'denied') {
    return (
      <Navigate
        replace
        to={clusterRootPath(curOrg.id || '', curCluster.id || '')}
      />
    )
  }
  if (resolution.decision !== 'v2') {
    return (
      <Navigate
        replace
        to={buildClinicStatementPath(
          curOrg.id || '',
          curCluster.id || '',
          'resolver',
          location.search
        )}
      />
    )
  }

  return <>{children}</>
}
