import {
  Alert,
  Badge,
  Box,
  Button,
  Card,
  Code,
  Group,
  Select,
  SimpleGrid,
  Stack,
  Switch,
  TextInput,
  Typography
} from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import {
  IconAlertTriangle,
  IconFileSearch02,
  IconRefreshCw01,
  IconSearchLg
} from '@tidbcloud/uikit/icons'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'

import {
  cloudConfigControllerListClusterConfigurationChanges,
  cloudConfigControllerSearchClusterComponents,
  listClusters,
  listResourcePools,
  useCloudConfigControllerListComponents,
  useCloudConfigControllerSearchClusterComponents,
  useRegionControllerListRegions
} from 'apiClient/services/devops'
import type {
  ClusterCluster,
  CloudConfigControllerListComponentsClusterType,
  CloudConfigControllerListClusterConfigurationChangesClusterType,
  CloudConfigControllerSearchClusterComponentsParams,
  CloudconfigClusterComponentSearchRegionResult,
  CloudconfigClusterComponentVersion,
  CloudconfigConfigurationChange,
  CloudconfigConfigurationChangePhase,
  CloudconfigConfigurationComponentChange
} from 'apiClient/services/devops/interface'
import {
  CloudConfigControllerSearchClusterComponentsClusterType,
  CloudconfigConfigurationChangePhase as ConfigurationChangePhase
} from 'apiClient/services/devops/interface'
import { getErrorMessage } from 'utils/error'

type SearchClusterType =
  CloudConfigControllerSearchClusterComponentsParams['cluster_type']

type Scope = 'global' | 'tenant'

type SearchFilters = {
  clusterType: SearchClusterType
  componentName: string
  componentVersion: string
  imageTag: string
  logicalRegion: string
}

type RegionPageState = {
  items: CloudconfigClusterComponentVersion[]
  pageIndex: number
  pageSize: number
  total?: number
}

type TablePaginationState = {
  pageIndex: number
  pageSize: number
}

type TablePaginationUpdater =
  | TablePaginationState
  | ((prev: TablePaginationState) => TablePaginationState)

type TenantClusterComponentRow = {
  clusterId: string
  components: Record<string, CloudconfigClusterComponentVersion[]>
  servicePlan?: string
}

type TenantComponentConfigChange = {
  changeId: number
  component: string
  createdAt?: number
  imageTag: string
}

type TenantComponentConfigChangeMap = Record<
  string,
  Record<string, TenantComponentConfigChange[]>
>

type TenantComponentDisplayOptions = {
  showImageTags: boolean
  showVersions: boolean
}

type ClusterMetadata = ClusterCluster

type Props = {
  fixedClusterType?: SearchClusterType
  scope: Scope
  tenantId?: string
}

const { DEDICATED_TIDB, TICDC, SHARED_POOL, LOGICAL_CLUSTER, TICDC_NG } =
  CloudConfigControllerSearchClusterComponentsClusterType

const PAGE_SIZE = 20
const TENANT_FETCH_PAGE_SIZE = 500
const CLUSTER_LOOKUP_PAGE_SIZE = 100
const CONFIG_CHANGE_LOOKBACK_SECONDS = 7 * 24 * 60 * 60
const CONFIG_CHANGE_PAGE_SIZE = 100
const CONFIG_CHANGE_PHASES_TO_SHOW =
  new Set<CloudconfigConfigurationChangePhase>([
    ConfigurationChangePhase.approving,
    ConfigurationChangePhase.wait_for_apply,
    ConfigurationChangePhase.applying
  ])

const CLUSTER_TYPE_OPTIONS = [
  { label: 'Dedicated', value: DEDICATED_TIDB },
  { label: 'TiCDC', value: TICDC },
  { label: 'Resource Pool', value: SHARED_POOL },
  { label: 'Premium & BYOC', value: LOGICAL_CLUSTER },
  { label: 'TiCDC NG', value: TICDC_NG }
]

const TENANT_CLUSTER_TYPE_OPTIONS = [
  { label: 'Resource Pool', value: SHARED_POOL },
  { label: 'Premium & BYOC', value: LOGICAL_CLUSTER }
]

const REGIONAL_CLUSTER_TYPES: SearchClusterType[] = [
  SHARED_POOL,
  LOGICAL_CLUSTER
]

const isRegionalClusterType = (clusterType: SearchClusterType) =>
  REGIONAL_CLUSTER_TYPES.includes(clusterType)

const getRegionResultKey = (
  regionResult: CloudconfigClusterComponentSearchRegionResult,
  index: number
) => regionResult.logical_region || `region-${index}`

const getValue = (value?: string) => {
  if (!value) {
    return (
      <Typography variant="body-sm" c="carbon.5">
        -
      </Typography>
    )
  }

  return (
    <Typography
      variant="body-sm"
      title={value}
      style={{
        maxWidth: 240,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        whiteSpace: 'nowrap'
      }}
    >
      {value}
    </Typography>
  )
}

const getCodeValue = (value?: string) => {
  if (!value) {
    return getValue()
  }

  return (
    <Code
      title={value}
      style={{
        display: 'inline-block',
        maxWidth: 240,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        verticalAlign: 'middle',
        whiteSpace: 'nowrap'
      }}
    >
      {value}
    </Code>
  )
}

const getHighlightedCodeValue = (value?: string) => {
  if (!value) {
    return getValue()
  }

  return (
    <Code
      title={value}
      style={{
        background: 'var(--mantine-color-peacock-0, #e7f5ff)',
        border: '1px solid var(--mantine-color-peacock-4, #4dabf7)',
        color: 'var(--mantine-color-peacock-8, #1864ab)',
        display: 'inline-block',
        fontWeight: 600,
        maxWidth: 240,
        overflow: 'hidden',
        textOverflow: 'ellipsis',
        verticalAlign: 'middle',
        whiteSpace: 'nowrap'
      }}
    >
      {value}
    </Code>
  )
}

const getCleanParams = (
  params: CloudConfigControllerSearchClusterComponentsParams
) =>
  Object.fromEntries(
    Object.entries(params).filter(
      ([, value]) => value !== undefined && value !== ''
    )
  ) as CloudConfigControllerSearchClusterComponentsParams

const getFixedPagination = (
  updaterOrValue: TablePaginationUpdater,
  currentPagination: TablePaginationState
) => {
  const nextPaginationValue =
    typeof updaterOrValue === 'function'
      ? updaterOrValue(currentPagination)
      : updaterOrValue

  return {
    pageIndex: nextPaginationValue.pageIndex,
    pageSize: PAGE_SIZE
  }
}

const getUniqueValues = (values: Array<string | undefined>) =>
  Array.from(new Set(values.filter((value): value is string => !!value))).sort()

const getValidTenantId = (tenantId?: string) =>
  tenantId && tenantId !== '0' ? tenantId : undefined

const getChunks = <T,>(items: T[], size: number) =>
  Array.from({ length: Math.ceil(items.length / size) }, (_, index) =>
    items.slice(index * size, index * size + size)
  )

const getClusterConfigurationChangesClusterType = (
  clusterType: SearchClusterType
) =>
  clusterType as CloudConfigControllerListClusterConfigurationChangesClusterType

const getComponentChangeToImageTag = (
  componentChange: CloudconfigConfigurationComponentChange
) =>
  componentChange.modified_image_tag?.to ||
  componentChange.modified_overwirte_image_tag?.to

const getConfigChangeDetailPath = (changeId: number) =>
  `/confighistories/${changeId}`

const appendTenantComponentConfigChange = (
  changeMap: TenantComponentConfigChangeMap,
  clusterId: string,
  change: CloudconfigConfigurationChange
) => {
  if (
    !change.id ||
    !change.scope?.components?.length ||
    !change.phase ||
    !CONFIG_CHANGE_PHASES_TO_SHOW.has(change.phase)
  ) {
    return
  }

  change.scope.components.forEach((componentChange) => {
    const component = componentChange.component
    const imageTag = getComponentChangeToImageTag(componentChange)

    if (!component || !imageTag) {
      return
    }

    changeMap[clusterId] = changeMap[clusterId] || {}
    changeMap[clusterId][component] = changeMap[clusterId][component] || []
    changeMap[clusterId][component].push({
      changeId: change.id!,
      component,
      createdAt: change.created_at,
      imageTag
    })
  })
}

const fetchResourcePoolMetadataByIds = async (
  ids: string[]
): Promise<ClusterMetadata[]> => {
  const responses = await Promise.all(
    getChunks(ids, CLUSTER_LOOKUP_PAGE_SIZE).map((resourcePoolIds) =>
      listResourcePools({
        page: 1,
        pagesize: resourcePoolIds.length,
        resource_pool_id: resourcePoolIds
      })
    )
  )

  return responses.flatMap((response) => response.data.items || [])
}

const getTenantComponentCellKey = (
  item: CloudconfigClusterComponentVersion,
  options: TenantComponentDisplayOptions
) =>
  [
    options.showVersions ? item.version || '' : '',
    options.showImageTags ? item.effective_image_tag || '' : ''
  ].join('|')

const getClusterTenantName = (cluster: ClusterMetadata | undefined) => {
  if (!cluster) {
    return undefined
  }

  return cluster.tenant_name || (cluster as any).tenantName
}

const getClusterServicePlan = (
  item: CloudconfigClusterComponentVersion,
  cluster: ClusterMetadata | undefined
) => cluster?.service_plan || (item as { service_plan?: string }).service_plan

const getTenantDetailPath = (tenantId?: string, tenantName?: string) => {
  if (!tenantId) {
    return undefined
  }

  const params = tenantName ? `?name=${encodeURIComponent(tenantName)}` : ''

  return `/orgs/${tenantId}${params}`
}

const getClusterDetailPath = (
  clusterId: string | undefined,
  cluster: ClusterMetadata | undefined,
  clusterType: SearchClusterType,
  fallbackTenantId?: string
) => {
  if (!clusterId) {
    return undefined
  }

  const tenantId = getValidTenantId(cluster?.tenant_id) || fallbackTenantId

  if (tenantId) {
    return `/orgs/${tenantId}/clusters/${clusterId}`
  }

  if (clusterType === SHARED_POOL) {
    return `/sharedResourcePool/${clusterId}`
  }

  return undefined
}

const renderEntityCell = (name?: string, id?: string, detailPath?: string) => (
  <Stack gap={2}>
    {name ? (
      detailPath ? (
        <Link rel="noopener noreferrer" target="_blank" to={detailPath}>
          {getValue(name)}
        </Link>
      ) : (
        getValue(name)
      )
    ) : (
      getValue()
    )}
    {id && (
      <Box>
        {detailPath ? (
          <Link rel="noopener noreferrer" target="_blank" to={detailPath}>
            {getCodeValue(id)}
          </Link>
        ) : (
          getCodeValue(id)
        )}
      </Box>
    )}
  </Stack>
)

const renderTenantComponentCell = (
  items: CloudconfigClusterComponentVersion[] | undefined,
  options: TenantComponentDisplayOptions,
  configChanges: TenantComponentConfigChange[] = []
) => {
  const visibleConfigChanges = options.showImageTags ? configChanges : []

  if (!items?.length && !visibleConfigChanges.length) {
    return getValue()
  }

  if (
    !options.showVersions &&
    !options.showImageTags &&
    !visibleConfigChanges.length
  ) {
    return getValue()
  }

  const dedupedItems = Array.from(
    new Map(
      (items || []).map((item) => [
        getTenantComponentCellKey(item, options),
        item
      ])
    ).values()
  )

  return (
    <Stack gap={6}>
      {dedupedItems.map((item) => {
        const values = [
          options.showVersions ? item.version : undefined,
          options.showImageTags ? item.effective_image_tag : undefined
        ].filter((value): value is string => !!value)

        return (
          <Stack key={getTenantComponentCellKey(item, options)} gap={2}>
            {values.length
              ? values.map((value) => (
                  <Box key={value}>{getCodeValue(value)}</Box>
                ))
              : getValue()}
          </Stack>
        )
      })}
      {visibleConfigChanges.map((change, index) => (
        <Group
          key={`${change.changeId}-${change.component}-${change.imageTag}-${index}`}
          gap={4}
        >
          <Typography
            variant="body-xs"
            c="peacock.7"
            style={{ fontWeight: 600 }}
          >
            To version
          </Typography>
          <Link
            rel="noopener noreferrer"
            target="_blank"
            style={{ textDecoration: 'none' }}
            to={getConfigChangeDetailPath(change.changeId)}
          >
            {getHighlightedCodeValue(change.imageTag)}
          </Link>
        </Group>
      ))}
    </Stack>
  )
}

export const ClusterComponentVersions = ({
  fixedClusterType,
  scope,
  tenantId
}: Props) => {
  const defaultClusterType =
    fixedClusterType || (scope === 'global' ? SHARED_POOL : LOGICAL_CLUSTER)
  const [clusterType, setClusterType] =
    useState<SearchClusterType>(defaultClusterType)
  const [componentName, setComponentName] = useState('')
  const [componentVersion, setComponentVersion] = useState('')
  const [imageTag, setImageTag] = useState('')
  const [logicalRegion, setLogicalRegion] = useState('')
  const [showVersions, setShowVersions] = useState(scope !== 'tenant')
  const [showImageTags, setShowImageTags] = useState(true)
  const [pagination, setPagination] = useState({
    pageIndex: 0,
    pageSize: PAGE_SIZE
  })
  const [tenantTablePagination, setTenantTablePagination] = useState({
    pageIndex: 0,
    pageSize: PAGE_SIZE
  })
  const [queryFilters, setQueryFilters] = useState<SearchFilters | null>(() =>
    scope === 'tenant'
      ? {
          clusterType: defaultClusterType,
          componentName: '',
          componentVersion: '',
          imageTag: '',
          logicalRegion: ''
        }
      : null
  )
  const [hasAutoSearched, setHasAutoSearched] = useState(false)
  const [regionPages, setRegionPages] = useState<
    Record<string, RegionPageState>
  >({})
  const [loadingRegion, setLoadingRegion] = useState('')
  const [tenantExtraItems, setTenantExtraItems] = useState<
    CloudconfigClusterComponentVersion[]
  >([])
  const [tenantExtraLoading, setTenantExtraLoading] = useState(false)
  const [tenantExtraError, setTenantExtraError] = useState<unknown>(null)
  const [clusterMetadataMap, setClusterMetadataMap] = useState<
    Record<string, ClusterMetadata>
  >({})
  const [clusterMetadataLoading, setClusterMetadataLoading] = useState(false)
  const [clusterMetadataSettledKey, setClusterMetadataSettledKey] = useState('')
  const [clusterMetadataError, setClusterMetadataError] =
    useState<unknown>(null)
  const [tenantConfigChangeMap, setTenantConfigChangeMap] =
    useState<TenantComponentConfigChangeMap>({})
  const [tenantConfigChangeLoading, setTenantConfigChangeLoading] =
    useState(false)
  const [tenantConfigChangeSettledKey, setTenantConfigChangeSettledKey] =
    useState('')
  const [tenantConfigChangeError, setTenantConfigChangeError] =
    useState<unknown>(null)
  const clusterTypeOptions =
    scope === 'tenant' ? TENANT_CLUSTER_TYPE_OPTIONS : CLUSTER_TYPE_OPTIONS

  useEffect(() => {
    if (!fixedClusterType) {
      return
    }

    setClusterType(fixedClusterType)
    if (scope === 'tenant') {
      setQueryFilters((prev) => ({
        clusterType: fixedClusterType,
        componentName: prev?.componentName || '',
        componentVersion: prev?.componentVersion || '',
        imageTag: prev?.imageTag || '',
        logicalRegion: ''
      }))
    }
  }, [fixedClusterType, scope])

  const { data: componentsResponse, isLoading: loadingComponents } =
    useCloudConfigControllerListComponents(
      {
        cluster_type:
          clusterType as CloudConfigControllerListComponentsClusterType
      },
      {
        query: {
          refetchOnWindowFocus: false
        }
      }
    )

  const components = useMemo(
    () => componentsResponse?.data?.components || [],
    [componentsResponse]
  )

  useEffect(() => {
    if (scope === 'global') {
      const firstComponent = components[0]
      if (firstComponent && !components.includes(componentName)) {
        setComponentName(firstComponent)
      }
      return
    }

    if (componentName && !components.includes(componentName)) {
      setComponentName('')
    }
  }, [componentName, components, scope])

  useEffect(() => {
    if (scope !== 'global' || hasAutoSearched || !componentName) {
      return
    }

    setHasAutoSearched(true)
    setPagination({ pageIndex: 0, pageSize: PAGE_SIZE })
    setQueryFilters({
      clusterType,
      componentName,
      componentVersion,
      imageTag,
      logicalRegion
    })
  }, [
    clusterType,
    componentName,
    componentVersion,
    hasAutoSearched,
    imageTag,
    logicalRegion,
    scope
  ])

  const isRegional = isRegionalClusterType(clusterType)

  const { data: regionsResponse, isLoading: loadingRegions } =
    useRegionControllerListRegions(
      { deploy_type: 'DEPLOY_TYPE_NEXTGEN' },
      {
        query: {
          enabled: scope === 'global' && isRegional,
          refetchOnWindowFocus: false
        }
      }
    )

  const regionOptions = useMemo(
    () =>
      (regionsResponse?.data?.regions || [])
        .map((item) => item.region?.logical_name)
        .filter((name): name is string => !!name)
        .map((name) => ({
          label: name,
          value: name
        })),
    [regionsResponse]
  )

  const queryParams = useMemo(() => {
    if (!queryFilters) {
      return {
        cluster_type: clusterType
      }
    }

    const regionalGlobal =
      scope === 'global' && isRegionalClusterType(queryFilters.clusterType)
    const allRegions = regionalGlobal && !queryFilters.logicalRegion

    return getCleanParams({
      cluster_type: queryFilters.clusterType,
      component_name: queryFilters.componentName,
      component_version: queryFilters.componentVersion,
      image_tag: queryFilters.imageTag,
      logical_region: queryFilters.logicalRegion,
      page: scope === 'tenant' || allRegions ? 1 : pagination.pageIndex + 1,
      per_page:
        scope === 'tenant' ? TENANT_FETCH_PAGE_SIZE : pagination.pageSize,
      region_mode: regionalGlobal
        ? queryFilters.logicalRegion
          ? 'single'
          : 'all'
        : undefined,
      tenant_id: scope === 'tenant' ? tenantId : undefined
    })
  }, [clusterType, pagination, queryFilters, scope, tenantId])

  const queryEnabled =
    !!queryFilters &&
    (scope === 'tenant' ? !!tenantId : !!queryFilters.componentName)

  const {
    data: searchResponse,
    error,
    isFetching,
    isLoading,
    isPreviousData,
    refetch
  } = useCloudConfigControllerSearchClusterComponents(queryParams, {
    query: {
      enabled: queryEnabled,
      keepPreviousData: true,
      refetchOnWindowFocus: false
    }
  })

  useEffect(() => {
    setRegionPages({})
  }, [queryFilters, pagination.pageSize])

  useEffect(() => {
    setTenantExtraItems([])
    setTenantExtraError(null)
  }, [queryFilters])

  const handleSearch = useCallback(() => {
    setPagination((prev) => ({ ...prev, pageIndex: 0 }))
    setTenantTablePagination((prev) => ({ ...prev, pageIndex: 0 }))
    setQueryFilters({
      clusterType,
      componentName,
      componentVersion,
      imageTag,
      logicalRegion
    })
  }, [clusterType, componentName, componentVersion, imageTag, logicalRegion])

  const handleReset = useCallback(() => {
    if (scope === 'tenant') {
      setComponentName('')
    }
    setComponentVersion('')
    setImageTag('')
    setLogicalRegion('')
    setPagination({ pageIndex: 0, pageSize: PAGE_SIZE })
    setTenantTablePagination({ pageIndex: 0, pageSize: PAGE_SIZE })
    setQueryFilters(
      scope === 'tenant'
        ? {
            clusterType,
            componentName: '',
            componentVersion: '',
            imageTag: '',
            logicalRegion: ''
          }
        : null
    )
  }, [clusterType, scope])

  const handleRegionPaginationChange = useCallback(
    async (
      regionResult: CloudconfigClusterComponentSearchRegionResult,
      index: number,
      updaterOrValue: TablePaginationUpdater
    ) => {
      if (!queryFilters || !regionResult.logical_region) {
        return
      }

      const region = regionResult.logical_region
      const regionKey = getRegionResultKey(regionResult, index)
      const currentPagination = {
        pageIndex: regionPages[regionKey]?.pageIndex || 0,
        pageSize: PAGE_SIZE
      }
      const nextPagination = getFixedPagination(
        updaterOrValue,
        currentPagination
      )

      if (nextPagination.pageIndex === currentPagination.pageIndex) {
        return
      }

      setLoadingRegion(regionKey)
      try {
        const response = await cloudConfigControllerSearchClusterComponents(
          getCleanParams({
            cluster_type: queryFilters.clusterType,
            component_name: queryFilters.componentName,
            component_version: queryFilters.componentVersion,
            image_tag: queryFilters.imageTag,
            logical_region: region,
            page: nextPagination.pageIndex + 1,
            per_page: PAGE_SIZE,
            region_mode: 'single',
            tenant_id: scope === 'tenant' ? tenantId : undefined
          })
        )
        const responseData = response.data
        const singleRegion = responseData.region_results?.[0]
        const nextItems =
          responseData.items || singleRegion?.items || ([] as any[])
        const total =
          singleRegion?.total || responseData.total || regionResult.total || 0

        setRegionPages((prev) => ({
          ...prev,
          [regionKey]: {
            items: nextItems,
            pageIndex: nextPagination.pageIndex,
            pageSize: PAGE_SIZE,
            total
          }
        }))
      } finally {
        setLoadingRegion('')
      }
    },
    [queryFilters, regionPages, scope, tenantId]
  )

  const responseData = searchResponse?.data

  useEffect(() => {
    if (
      scope !== 'tenant' ||
      !queryFilters ||
      !tenantId ||
      !responseData ||
      isLoading ||
      isFetching
    ) {
      return
    }

    const total = responseData.total || 0
    const firstPageItems = responseData.items || []
    const pageCount = Math.ceil(total / TENANT_FETCH_PAGE_SIZE)
    if (pageCount <= 1 || firstPageItems.length >= total) {
      setTenantExtraItems([])
      setTenantExtraLoading(false)
      setTenantExtraError(null)
      return
    }

    let canceled = false

    const fetchRemainingPages = async () => {
      setTenantExtraLoading(true)
      setTenantExtraError(null)
      try {
        const pageNumbers = Array.from(
          { length: pageCount - 1 },
          (_, index) => index + 2
        )
        const responses = await Promise.all(
          pageNumbers.map((page) =>
            cloudConfigControllerSearchClusterComponents(
              getCleanParams({
                cluster_type: queryFilters.clusterType,
                component_name: queryFilters.componentName,
                component_version: queryFilters.componentVersion,
                image_tag: queryFilters.imageTag,
                page,
                per_page: TENANT_FETCH_PAGE_SIZE,
                tenant_id: tenantId
              })
            )
          )
        )
        const nextItems = responses.flatMap(
          (response) => response.data.items || []
        )
        if (!canceled) {
          setTenantExtraItems(nextItems)
        }
      } catch (nextError) {
        if (!canceled) {
          setTenantExtraError(nextError)
        }
      } finally {
        if (!canceled) {
          setTenantExtraLoading(false)
        }
      }
    }

    fetchRemainingPages()

    return () => {
      canceled = true
    }
  }, [isFetching, isLoading, queryFilters, responseData, scope, tenantId])

  const allRegionQuery =
    queryFilters &&
    scope === 'global' &&
    isRegionalClusterType(queryFilters.clusterType) &&
    !queryFilters.logicalRegion
  const rawRegionResults = useMemo(
    () => responseData?.region_results || [],
    [responseData?.region_results]
  )
  const sortedRegionResults = useMemo(
    () =>
      rawRegionResults
        .map((regionResult, index) => {
          const regionKey = getRegionResultKey(regionResult, index)
          const total = regionPages[regionKey]?.total ?? regionResult.total ?? 0

          return {
            failed: !!regionResult.error,
            index,
            regionResult,
            total
          }
        })
        .sort(
          (left, right) =>
            Number(left.failed) - Number(right.failed) ||
            right.total - left.total ||
            left.index - right.index
        ),
    [rawRegionResults, regionPages]
  )
  const showRegionResults = allRegionQuery && sortedRegionResults.length > 0
  const flatItems = useMemo(
    () =>
      showRegionResults
        ? []
        : responseData?.items ||
          responseData?.region_results?.flatMap(
            (region) => region.items || []
          ) ||
          [],
    [responseData?.items, responseData?.region_results, showRegionResults]
  )
  const showFlatEmpty = !isLoading && !isFetching && flatItems.length === 0
  const tenantItems = useMemo(
    () =>
      scope === 'tenant'
        ? [...(responseData?.items || []), ...tenantExtraItems]
        : [],
    [responseData?.items, scope, tenantExtraItems]
  )
  const clusterItemsForLookup = useMemo(() => {
    if (scope === 'tenant') {
      return tenantItems
    }

    if (showRegionResults) {
      return sortedRegionResults.flatMap(({ regionResult, index }) => {
        const regionKey = getRegionResultKey(regionResult, index)

        return regionPages[regionKey]?.items || regionResult.items || []
      })
    }

    return flatItems
  }, [
    flatItems,
    regionPages,
    scope,
    showRegionResults,
    sortedRegionResults,
    tenantItems
  ])
  const clusterIdsForLookup = useMemo(
    () => getUniqueValues(clusterItemsForLookup.map((item) => item.cluster_id)),
    [clusterItemsForLookup]
  )
  const clusterIdsForLookupKey = clusterIdsForLookup.join('|')
  const activeResultClusterType = queryFilters?.clusterType || clusterType

  useEffect(() => {
    if (isPreviousData) {
      setClusterMetadataLoading(false)
      return
    }

    if (!clusterIdsForLookupKey) {
      setClusterMetadataMap({})
      setClusterMetadataLoading(false)
      setClusterMetadataSettledKey('')
      setClusterMetadataError(null)
      return
    }

    let canceled = false
    const ids = clusterIdsForLookupKey.split('|')
    const isResourcePoolLookup = activeResultClusterType === SHARED_POOL

    const fetchClusterMetadata = async () => {
      setClusterMetadataLoading(true)
      setClusterMetadataError(null)
      try {
        const metadataItems = isResourcePoolLookup
          ? await fetchResourcePoolMetadataByIds(ids)
          : (
              await Promise.all(
                getChunks(ids, CLUSTER_LOOKUP_PAGE_SIZE).map((clusterIds) =>
                  listClusters({
                    cluster_id: clusterIds,
                    page: 1,
                    per_page: clusterIds.length
                  })
                )
              )
            ).flatMap((response) => response.data.items || [])

        if (canceled) {
          return
        }

        setClusterMetadataMap(
          Object.fromEntries(
            metadataItems
              .filter((cluster): cluster is ClusterMetadata => !!cluster.id)
              .map((cluster) => [cluster.id!, cluster])
          )
        )
        setClusterMetadataSettledKey(clusterIdsForLookupKey)
      } catch (nextError) {
        if (!canceled) {
          setClusterMetadataError(nextError)
          setClusterMetadataMap({})
          setClusterMetadataSettledKey(clusterIdsForLookupKey)
        }
      } finally {
        if (!canceled) {
          setClusterMetadataLoading(false)
        }
      }
    }

    fetchClusterMetadata()

    return () => {
      canceled = true
    }
  }, [activeResultClusterType, clusterIdsForLookupKey, isPreviousData])

  const tenantComponentNames = useMemo(() => {
    if (queryFilters?.componentName) {
      return [queryFilters.componentName]
    }

    const componentOrder = new Map(
      components.map((component, index) => [component, index])
    )
    const changedComponents = Object.values(tenantConfigChangeMap).flatMap(
      (clusterChanges) => Object.keys(clusterChanges)
    )

    return Array.from(
      new Set([
        ...tenantItems
          .map((item) => item.component_name)
          .filter((component): component is string => !!component),
        ...changedComponents
      ])
    ).sort((left, right) => {
      const leftOrder = componentOrder.get(left) ?? Number.MAX_SAFE_INTEGER
      const rightOrder = componentOrder.get(right) ?? Number.MAX_SAFE_INTEGER
      return leftOrder - rightOrder || left.localeCompare(right)
    })
  }, [
    components,
    queryFilters?.componentName,
    tenantConfigChangeMap,
    tenantItems
  ])
  const tenantRows = useMemo<TenantClusterComponentRow[]>(() => {
    const rowMap = new Map<string, TenantClusterComponentRow>()

    tenantItems.forEach((item) => {
      if (!item.cluster_id || !item.component_name) {
        return
      }

      const row = rowMap.get(item.cluster_id) || {
        clusterId: item.cluster_id,
        components: {},
        servicePlan: (item as { service_plan?: string }).service_plan
      }
      row.servicePlan =
        row.servicePlan || (item as { service_plan?: string }).service_plan
      row.components[item.component_name] = [
        ...(row.components[item.component_name] || []),
        item
      ]
      rowMap.set(item.cluster_id, row)
    })

    return Array.from(rowMap.values()).sort((left, right) =>
      left.clusterId.localeCompare(right.clusterId)
    )
  }, [tenantItems])
  const tenantConfigChangeClusterIds = useMemo(
    () =>
      scope === 'tenant'
        ? tenantRows.map((row) => row.clusterId).filter(Boolean)
        : [],
    [scope, tenantRows]
  )
  const tenantConfigChangeLookupKey = [
    activeResultClusterType,
    ...tenantConfigChangeClusterIds
  ].join('|')
  const activeTenantConfigChangeLookupKey =
    tenantConfigChangeClusterIds.length > 0 ? tenantConfigChangeLookupKey : ''

  useEffect(() => {
    if (scope !== 'tenant' || !activeTenantConfigChangeLookupKey) {
      setTenantConfigChangeMap({})
      setTenantConfigChangeLoading(false)
      setTenantConfigChangeSettledKey('')
      setTenantConfigChangeError(null)
      return
    }

    let canceled = false
    const clusterIds = tenantConfigChangeClusterIds
    const now = Math.floor(Date.now() / 1000)
    const clusterTypeForChanges = getClusterConfigurationChangesClusterType(
      activeResultClusterType
    )

    const fetchClusterChanges = async (clusterId: string) => {
      const params = {
        cluster_id: clusterId,
        cluster_type: clusterTypeForChanges,
        created_at_end_unix_sec: now,
        created_at_start_unix_sec: now - CONFIG_CHANGE_LOOKBACK_SECONDS,
        page: 1,
        per_page: CONFIG_CHANGE_PAGE_SIZE
      }
      const firstPage = (
        await cloudConfigControllerListClusterConfigurationChanges(params)
      ).data
      const firstPageItems = firstPage.items || []
      const total = firstPage.total || firstPageItems.length
      const pageCount = Math.ceil(total / CONFIG_CHANGE_PAGE_SIZE)

      if (pageCount <= 1) {
        return firstPageItems
      }

      const remainingResponses = await Promise.all(
        Array.from({ length: pageCount - 1 }, (_, index) =>
          cloudConfigControllerListClusterConfigurationChanges({
            ...params,
            page: index + 2
          })
        )
      )

      return [
        ...firstPageItems,
        ...remainingResponses.flatMap((response) => response.data.items || [])
      ]
    }

    const fetchTenantConfigChanges = async () => {
      setTenantConfigChangeLoading(true)
      setTenantConfigChangeError(null)

      try {
        const results = await Promise.allSettled(
          clusterIds.map(async (clusterId) => ({
            changes: await fetchClusterChanges(clusterId),
            clusterId
          }))
        )
        const nextMap: TenantComponentConfigChangeMap = {}
        const failedResult = results.find(
          (result) => result.status === 'rejected'
        )

        results.forEach((result) => {
          if (result.status !== 'fulfilled') {
            return
          }

          result.value.changes.forEach((change) => {
            appendTenantComponentConfigChange(
              nextMap,
              result.value.clusterId,
              change
            )
          })
        })

        Object.values(nextMap).forEach((clusterChanges) => {
          Object.values(clusterChanges).forEach((changes) => {
            changes.sort(
              (left, right) => (right.createdAt || 0) - (left.createdAt || 0)
            )
          })
        })

        if (canceled) {
          return
        }

        setTenantConfigChangeMap(nextMap)
        setTenantConfigChangeSettledKey(activeTenantConfigChangeLookupKey)
        setTenantConfigChangeError(
          failedResult?.status === 'rejected' ? failedResult.reason : null
        )
      } finally {
        if (!canceled) {
          setTenantConfigChangeLoading(false)
        }
      }
    }

    fetchTenantConfigChanges()

    return () => {
      canceled = true
    }
  }, [
    activeResultClusterType,
    activeTenantConfigChangeLookupKey,
    scope,
    tenantConfigChangeClusterIds
  ])
  const tenantComponentDisplayOptions = useMemo(
    () => ({ showImageTags, showVersions }),
    [showImageTags, showVersions]
  )
  const columns = useMemo<MRT_ColumnDef<CloudconfigClusterComponentVersion>[]>(
    () => [
      {
        header: 'Tenant',
        accessorKey: 'tenant_id',
        size: 260,
        Cell: ({ row }) => {
          const cluster = row.original.cluster_id
            ? clusterMetadataMap[row.original.cluster_id]
            : undefined
          const tenantName = getClusterTenantName(cluster)
          const tenantId = getValidTenantId(cluster?.tenant_id)

          return renderEntityCell(
            tenantName,
            tenantId,
            getTenantDetailPath(tenantId, tenantName)
          )
        }
      },
      {
        header: 'Cluster',
        accessorKey: 'cluster_id',
        size: 260,
        Cell: ({ row }) => {
          const cluster = row.original.cluster_id
            ? clusterMetadataMap[row.original.cluster_id]
            : undefined

          return renderEntityCell(
            cluster?.name,
            row.original.cluster_id,
            getClusterDetailPath(
              row.original.cluster_id,
              cluster,
              activeResultClusterType,
              scope === 'tenant' ? tenantId : undefined
            )
          )
        }
      },
      {
        header: 'Service Plan',
        id: 'service_plan',
        size: 140,
        Cell: ({ row }) => {
          const cluster = row.original.cluster_id
            ? clusterMetadataMap[row.original.cluster_id]
            : undefined

          return getValue(getClusterServicePlan(row.original, cluster))
        }
      },
      {
        header: 'Component',
        accessorKey: 'component_name',
        size: 140,
        Cell: ({ row }) => getValue(row.original.component_name)
      },
      {
        header: 'Version',
        accessorKey: 'version',
        size: 140,
        Cell: ({ row }) => getCodeValue(row.original.version)
      },
      {
        header: 'Effective Tag',
        accessorKey: 'effective_image_tag',
        size: 220,
        Cell: ({ row }) => getCodeValue(row.original.effective_image_tag)
      }
    ],
    [activeResultClusterType, clusterMetadataMap, scope, tenantId]
  )
  const tenantColumns = useMemo<MRT_ColumnDef<TenantClusterComponentRow>[]>(
    () => [
      {
        header: 'Cluster',
        accessorKey: 'clusterId',
        size: 260,
        Cell: ({ row }) =>
          renderEntityCell(
            clusterMetadataMap[row.original.clusterId]?.name,
            row.original.clusterId,
            getClusterDetailPath(
              row.original.clusterId,
              clusterMetadataMap[row.original.clusterId],
              activeResultClusterType,
              tenantId
            )
          )
      },
      {
        header: 'Service Plan',
        id: 'service_plan',
        size: 140,
        Cell: ({ row }) =>
          getValue(
            clusterMetadataMap[row.original.clusterId]?.service_plan ||
              row.original.servicePlan
          )
      },
      ...tenantComponentNames.map<MRT_ColumnDef<TenantClusterComponentRow>>(
        (component) => ({
          header: component,
          id: `component-${component}`,
          size: 220,
          Cell: ({ row }) =>
            renderTenantComponentCell(
              row.original.components[component],
              tenantComponentDisplayOptions,
              tenantConfigChangeMap[row.original.clusterId]?.[component]
            )
        })
      )
    ],
    [
      activeResultClusterType,
      clusterMetadataMap,
      tenantConfigChangeMap,
      tenantComponentDisplayOptions,
      tenantComponentNames,
      tenantId
    ]
  )
  const metadataLoading =
    clusterMetadataLoading ||
    (!!clusterIdsForLookupKey &&
      clusterMetadataSettledKey !== clusterIdsForLookupKey)
  const configChangeLoading =
    tenantConfigChangeLoading ||
    (!!activeTenantConfigChangeLookupKey &&
      tenantConfigChangeSettledKey !== activeTenantConfigChangeLookupKey)
  const tenantTableLoading =
    isLoading ||
    isFetching ||
    tenantExtraLoading ||
    metadataLoading ||
    configChangeLoading
  const flatTableLoading = isLoading || isFetching || metadataLoading
  const showTenantEmpty = !tenantTableLoading && tenantRows.length === 0
  const shouldPaginateTenantRows = tenantRows.length > PAGE_SIZE

  return (
    <Stack gap="md">
      <Card withBorder shadow="xs" padding="md" radius="sm">
        <Stack gap="md">
          <Group justify="space-between" align="flex-start">
            <Stack gap={4}>
              <Typography variant="title-md">
                Cluster Component Versions
              </Typography>
              <Typography variant="body-sm" c="carbon.6">
                {scope === 'tenant'
                  ? 'Search component versions under this tenant.'
                  : 'Search component versions across config center.'}
              </Typography>
            </Stack>
            {queryFilters && (
              <Button
                variant="default"
                leftSection={<IconRefreshCw01 size={16} />}
                loading={isFetching}
                onClick={() => refetch()}
              >
                Refresh
              </Button>
            )}
          </Group>

          <SimpleGrid cols={{ base: 1, sm: 2, lg: 5 }} spacing="sm">
            <Select
              label="Cluster Type"
              data={clusterTypeOptions}
              disabled={scope !== 'tenant' && !!fixedClusterType}
              value={clusterType}
              onChange={(value) => {
                const nextClusterType = (value || defaultClusterType) as
                  | SearchClusterType
                  | undefined
                if (!nextClusterType) {
                  return
                }
                setClusterType(nextClusterType)
                setComponentName('')
                setLogicalRegion('')
                if (scope === 'tenant') {
                  setQueryFilters((prev) => ({
                    clusterType: nextClusterType,
                    componentName: '',
                    componentVersion: prev?.componentVersion || '',
                    imageTag: prev?.imageTag || '',
                    logicalRegion: ''
                  }))
                }
              }}
            />
            <Select
              label="Component"
              placeholder={scope === 'tenant' ? 'All components' : undefined}
              clearable={scope === 'tenant'}
              data={components.map((component) => ({
                label: component,
                value: component
              }))}
              disabled={loadingComponents}
              value={componentName || null}
              onChange={(value) => setComponentName(value || '')}
              searchable
              required={scope === 'global'}
            />
            <TextInput
              label="Component Version"
              placeholder="Optional"
              value={componentVersion}
              onChange={(event) =>
                setComponentVersion(event.currentTarget.value)
              }
            />
            <TextInput
              label="Image Tag"
              placeholder="Optional"
              value={imageTag}
              onChange={(event) => setImageTag(event.currentTarget.value)}
            />
            {scope === 'global' && isRegional ? (
              <Select
                label="Logical Region"
                placeholder="All regions"
                clearable
                data={regionOptions}
                disabled={loadingRegions}
                value={logicalRegion || null}
                onChange={(value) => setLogicalRegion(value || '')}
                searchable
              />
            ) : (
              <Box />
            )}
          </SimpleGrid>

          <Group justify={scope === 'tenant' ? 'space-between' : 'flex-end'}>
            {scope === 'tenant' && (
              <Group gap="md">
                <Switch
                  label="Show versions"
                  checked={showVersions}
                  onChange={(event) =>
                    setShowVersions(event.currentTarget.checked)
                  }
                />
                <Switch
                  label="Show image tag"
                  checked={showImageTags}
                  onChange={(event) =>
                    setShowImageTags(event.currentTarget.checked)
                  }
                />
              </Group>
            )}
            <Group gap="sm">
              <Button variant="default" onClick={handleReset}>
                Reset
              </Button>
              <Button
                leftSection={<IconSearchLg size={16} />}
                onClick={handleSearch}
                disabled={scope === 'global' && !componentName}
              >
                Search
              </Button>
            </Group>
          </Group>
        </Stack>
      </Card>

      {!!error && (
        <Alert
          color="red"
          variant="light"
          icon={<IconAlertTriangle size={16} />}
          title="Search failed"
        >
          {getErrorMessage(error)}
        </Alert>
      )}

      {!!tenantExtraError && (
        <Alert
          color="red"
          variant="light"
          icon={<IconAlertTriangle size={16} />}
          title="Search failed"
        >
          {getErrorMessage(tenantExtraError)}
        </Alert>
      )}

      {!!clusterMetadataError && (
        <Alert
          color="red"
          variant="light"
          icon={<IconAlertTriangle size={16} />}
          title="Cluster metadata lookup failed"
        >
          {getErrorMessage(clusterMetadataError)}
        </Alert>
      )}

      {!!tenantConfigChangeError && (
        <Alert
          color="red"
          variant="light"
          icon={<IconAlertTriangle size={16} />}
          title="Config change lookup failed"
        >
          {getErrorMessage(tenantConfigChangeError)}
        </Alert>
      )}

      {showRegionResults ? (
        <Stack gap="md">
          <Group justify="space-between">
            <Group gap="xs">
              <IconFileSearch02 size={16} />
              <Typography variant="title-sm">All-region results</Typography>
            </Group>
            <Group gap="xs">
              <Badge variant="light">{responseData?.total || 0} total</Badge>
              {responseData?.partial_failure && (
                <Badge color="orange" variant="light">
                  Partial failure
                </Badge>
              )}
            </Group>
          </Group>

          {sortedRegionResults.map(({ regionResult, index }) => {
            const regionKey = getRegionResultKey(regionResult, index)
            const regionPageState = regionPages[regionKey]
            const items = regionPageState?.items || regionResult.items || []
            const total = regionPageState?.total ?? regionResult.total ?? 0
            const regionPagination = {
              pageIndex: regionPageState?.pageIndex || 0,
              pageSize: PAGE_SIZE
            }

            return (
              <Card key={regionKey} withBorder shadow="xs" padding="md">
                <Stack gap="md">
                  <Stack gap={4}>
                    <Group gap="xs">
                      <Typography variant="title-sm">
                        {regionResult.logical_region || 'Unknown region'}
                      </Typography>
                      {regionResult.error ? (
                        <Badge color="red" variant="light">
                          Failed
                        </Badge>
                      ) : (
                        <Badge variant="light">{total} total</Badge>
                      )}
                    </Group>
                    {regionResult.error && (
                      <Typography variant="body-sm" c="red.6">
                        {regionResult.error}
                      </Typography>
                    )}
                  </Stack>

                  <ProTable<CloudconfigClusterComponentVersion>
                    columns={columns}
                    data={metadataLoading ? [] : items}
                    enableColumnActions={false}
                    enableColumnFilters={false}
                    enableDensityToggle={false}
                    enableFullScreenToggle={false}
                    enableHiding={false}
                    enablePagination={total > PAGE_SIZE}
                    enableSorting={false}
                    enableTopToolbar={false}
                    getRowId={(row, rowIndex) =>
                      [
                        row.cluster_id,
                        row.component_name,
                        row.version,
                        row.node_instance,
                        rowIndex
                      ].join('-')
                    }
                    loading={
                      metadataLoading ||
                      loadingRegion === regionKey ||
                      (isLoading && !items.length)
                    }
                    manualPagination
                    onPaginationChange={(updaterOrValue) => {
                      void handleRegionPaginationChange(
                        regionResult,
                        index,
                        updaterOrValue as TablePaginationUpdater
                      )
                    }}
                    pagination={{ showRowsPerPage: false }}
                    rowCount={total}
                    state={{ pagination: regionPagination }}
                  />
                </Stack>
              </Card>
            )
          })}
        </Stack>
      ) : scope === 'tenant' ? (
        <Box
          style={{
            position: 'relative'
          }}
        >
          <ProTable<TenantClusterComponentRow>
            columns={tenantColumns}
            data={metadataLoading ? [] : tenantRows}
            enableColumnActions={false}
            enableColumnFilters={false}
            enableDensityToggle={false}
            enableFullScreenToggle={false}
            enableHiding={false}
            enablePagination={shouldPaginateTenantRows}
            enableSorting={false}
            enableTopToolbar={false}
            getRowId={(row) => row.clusterId}
            loading={tenantTableLoading}
            onPaginationChange={(updaterOrValue) => {
              setTenantTablePagination((prev) =>
                getFixedPagination(
                  updaterOrValue as TablePaginationUpdater,
                  prev
                )
              )
            }}
            pagination={{ showRowsPerPage: false }}
            rowCount={shouldPaginateTenantRows ? tenantRows.length : undefined}
            state={{ pagination: tenantTablePagination }}
            mantineTableContainerProps={{
              sx: { minHeight: 168 }
            }}
            renderEmptyRowsFallback={() => null}
          />
          {showTenantEmpty && (
            <Box
              style={{
                alignItems: 'center',
                display: 'flex',
                height: 112,
                justifyContent: 'center',
                left: 0,
                pointerEvents: 'none',
                position: 'absolute',
                right: 0,
                top: 46
              }}
            >
              <Stack align="center" gap={4}>
                <Typography variant="title-sm">
                  No component versions found
                </Typography>
                <Typography variant="body-sm" c="carbon.6">
                  Try adjusting the search filters.
                </Typography>
              </Stack>
            </Box>
          )}
        </Box>
      ) : (
        <Box
          style={{
            position: 'relative'
          }}
        >
          <ProTable<CloudconfigClusterComponentVersion>
            columns={columns}
            data={metadataLoading ? [] : flatItems}
            enableColumnActions={false}
            enableColumnFilters={false}
            enableDensityToggle={false}
            enableFullScreenToggle={false}
            enableHiding={false}
            enablePagination={
              queryEnabled && (responseData?.total || 0) > PAGE_SIZE
            }
            enableSorting={false}
            enableTopToolbar={false}
            getRowId={(row, rowIndex) =>
              [
                row.cluster_id,
                row.component_name,
                row.version,
                row.node_instance,
                row.logical_region,
                rowIndex
              ].join('-')
            }
            loading={flatTableLoading}
            manualPagination
            onPaginationChange={setPagination}
            pagination={{ showRowsPerPage: false }}
            rowCount={responseData?.total || 0}
            state={{ pagination }}
            mantineTableContainerProps={{
              sx: { minHeight: 168 }
            }}
            renderEmptyRowsFallback={() => null}
          />
          {showFlatEmpty && (
            <Box
              style={{
                alignItems: 'center',
                display: 'flex',
                height: 112,
                justifyContent: 'center',
                left: 0,
                pointerEvents: 'none',
                position: 'absolute',
                right: 0,
                top: 46
              }}
            >
              <Stack align="center" gap={4}>
                <Typography variant="title-sm">
                  {queryFilters ? 'No component versions found' : 'No search'}
                </Typography>
                <Typography variant="body-sm" c="carbon.6">
                  {queryFilters
                    ? 'Try adjusting the search filters.'
                    : 'Select the required fields and run a search.'}
                </Typography>
              </Stack>
            </Box>
          )}
        </Box>
      )}
    </Stack>
  )
}
