import {
  ActionIcon,
  Box,
  Button,
  Combobox,
  Divider,
  Flex,
  Group,
  Highlight,
  HoverCard,
  Input,
  Menu,
  ScrollArea,
  Skeleton,
  Stack,
  Typography
} from '@tidbcloud/uikit'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import {
  IconCheck,
  IconChevronDown,
  IconChevronRight,
  IconFolder,
  IconPlus,
  IconSearchMd,
  IconSettings02,
  IconDProjectFill,
  IconFlipBackward
} from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useEffect, useMemo, useState } from 'react'
import { useHistory } from 'react-router-dom'

import { log } from 'common/log'
import { getBFFTiDB } from 'dbaas/features/ClusterManagement/tidb'
import { ProjectType } from 'dbaas/features/Project'
import { useVirtualProjectId } from 'dbaas/screens/NextGen/my-tidb-creation/shared/use-virtual-project-id'
import { useCreateResourceAccess } from 'dbaas/screens/NextGen/shared/access/use-create-resource-access'
import { ServicePlanTag } from 'dbaas/screens/NextGen/shared/tidb-instance/service-plan/ServicePlanTag'
import { CentralUserProfileOrg, CentralUserProfileProject } from 'dbaas/services/account/interface'
import { useTiDBServiceListTidbs } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta2'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import { NEXTGEN_ORG_INDEX_PATH } from '../shared/useEnterpriseOrgSwitch'

import { useCurrentTiDB, useGetCurrentTidbId } from './useCurrentTiDB'
import { PROJECT_SETTINGS_PATH, useClusterSwitch, useProjectSwitch } from './useNavigationSwitch'

const CREATE_CLUSTER_PATH = '/tidbs/new'
const escapeDomValue = (value: string) => {
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
  const esc = (globalThis as any)?.CSS?.escape
  return esc ? esc(value) : value.replace(/"/g, '\\"')
}

export const ClusterPanel = observer(
  ({
    org,
    onNavigation
  }: {
    org: CentralUserProfileOrg
    onNavigation: (clusterId: string) => void
    onBack: () => void
  }) => {
    const { data: tidb } = useCurrentTiDB()
    const history = useHistory()
    const {
      store: {
        lastVisitLocation: { orgId }
      }
    } = useStores()
    const [search, setSearch] = useState('')

    const createResourceAccess = useCreateResourceAccess()
    const isCreateDisabled = orgId !== org.id || !createResourceAccess

    return (
      <Box h={354}>
        <Stack gap={4} pr={8}>
          <Group justify="space-between" gap={4} mb={4}>
            {/* <ActionIcon variant="subtle" color="carbon" size="md" onClick={onBack}>
              <IconArrowLeft />
            </ActionIcon> */}
            <Button
              variant="subtle"
              color="carbon"
              size="xs"
              leftSection={<IconFlipBackward size={16} c="carbon.8" />}
              px={8}
              w={'100%'}
              styles={(theme) => ({
                label: { color: theme.colors.carbon[8] },
                root: {
                  '&:hover': {
                    backgroundColor: `${theme.colors.carbon[3]} !important`
                  }
                },
                inner: {
                  justifyContent: 'flex-start'
                }
              })}
              onClick={() => {
                eventTracking('Click back to My TiDB', {
                  source: 'Global Side Navbar Switcher NextGen - Cluster Panel'
                })
                onNavigation(tidb?.tidbId || '')
                history.push(NEXTGEN_ORG_INDEX_PATH)
              }}
            >
              <Typography variant="body-lg" c="carbon.8">
                Back to My TiDB
              </Typography>
            </Button>
          </Group>
          <Input
            sx={{ flexGrow: 1 }}
            size="sm"
            placeholder="Find Instance / Cluster"
            leftSection={<IconSearchMd size={16} c="gray.9" />}
            value={search}
            onChange={(e) => setSearch(e.currentTarget.value)}
            onClick={() => {
              eventTracking('Click search cluster', {
                source: 'Global Side Navbar Switcher NextGen - Cluster Panel'
              })
            }}
          />
          <ScrollArea.Autosize
            type="scroll"
            mr={-8}
            h={355}
            scrollbarSize="var(--combobox-padding)"
            offsetScrollbars="y"
          >
            <ProjectClusterList search={search.trim()} org={org} onNavigation={onNavigation} />
          </ScrollArea.Autosize>

          <Divider />

          <HoverCard disabled={!isCreateDisabled}>
            <HoverCard.Target>
              <Box>
                <Button
                  w="100%"
                  variant="transparent"
                  color="peacock"
                  size="sm"
                  disabled={isCreateDisabled}
                  onClick={() => {
                    eventTracking('Click create cluster', {
                      source: 'Global Side Navbar Switcher NextGen - Cluster Panel'
                    })
                    onNavigation(org.id)
                    history.push(CREATE_CLUSTER_PATH)
                  }}
                >
                  <Group gap={4}>
                    <IconPlus size={16} />
                    <Box>Create Resource</Box>
                  </Group>
                </Button>
              </Box>
            </HoverCard.Target>
            <HoverCard.Dropdown py={4}>
              {!createResourceAccess
                ? 'You do not have sufficient permissions.'
                : 'Switch to this organization to create resource'}
            </HoverCard.Dropdown>
          </HoverCard>
        </Stack>
      </Box>
    )
  }
)

const CLUSTER_NUM_PER_PAGE = 100

const ProjectClusterList = observer(
  ({
    search,
    org,
    onNavigation
  }: {
    search: string
    org: CentralUserProfileOrg
    onNavigation: (clusterId: string) => void
  }) => {
    const {
      store: {
        allProjects,
        lastVisitLocation: { projectId }
      }
    } = useStores()
    const currentTidbId = useGetCurrentTidbId()

    const visibleProjects = useMemo(() => {
      const orgProjects = allProjects.filter((p) => p.org_id === org.id && p.type !== ProjectType.TIDBX_VIRTUAL)
      if (!search) {
        return orgProjects
      }
      return orgProjects.filter((p) => p.name.toLowerCase().includes(search.toLowerCase()))
    }, [allProjects, org.id, search])

    const virtualProjectId = useVirtualProjectId()

    // @TODO remember to add the out of project project when M2 ready
    const outOfProjectProject = virtualProjectId
      ? {
          id: virtualProjectId,
          name: '(Out of project)',
          org_id: org.id,
          is_cross_account: false,
          type: ProjectType.TIDBX_VIRTUAL
        }
      : undefined

    useEffect(() => {
      if (currentTidbId) return

      if (projectId === undefined || projectId === null) return
      const targetId = projectId || '0'
      const el = document.querySelector<HTMLElement>(`[data-nav-switcher-project-id="${escapeDomValue(targetId)}"]`)
      el?.scrollIntoView({ block: 'nearest' })
    }, [currentTidbId, projectId, search, virtualProjectId])

    return (
      <Menu>
        {outOfProjectProject && (
          <ProjectClusterListItem
            key={outOfProjectProject.id}
            project={outOfProjectProject}
            org={org}
            search={search}
            onNavigation={onNavigation}
            isProjectSelected={projectId === outOfProjectProject.id || (!projectId && outOfProjectProject.id === '0')}
          />
        )}
        {visibleProjects.map((project) => {
          return (
            <ProjectClusterListItem
              key={project.id}
              project={project}
              org={org}
              search={search}
              onNavigation={onNavigation}
              isProjectSelected={projectId === project.id}
            />
          )
        })}
      </Menu>
    )
  }
)

const ProjectClusterListItem = observer(
  ({
    project,
    org,
    search,
    onNavigation,
    isProjectSelected
  }: {
    project: CentralUserProfileProject
    org: CentralUserProfileOrg
    search: string
    onNavigation: (clusterId: string) => void
    isProjectSelected: boolean
  }) => {
    const { data: tidb } = useCurrentTiDB()
    const currentTidbId = useGetCurrentTidbId()
    const [opened, { open, toggle }] = useDisclosure(isProjectSelected)
    const projectSwitch = useProjectSwitch()
    const clusterSwitch = useClusterSwitch()
    const history = useHistory()
    const {
      store: {
        lastVisitLocation: { orgId }
      },
      actions: { updateLastVisitLocation }
    } = useStores()
    const isOtherOrgSwitch = orgId !== org.id

    const { data, isLoading } = useTiDBServiceListTidbs(
      {
        orgId: org.id,
        projectIds: project.type === ProjectType.TIDBX_VIRTUAL ? [project.id, '0'] : [project.id],
        pageSize: CLUSTER_NUM_PER_PAGE,
        skip: 0
      },
      {
        query: {
          enabled: !!org.id && !!project.id && opened,
          refetchOnWindowFocus: false,
          onError: (err) => {
            log.error('Failed to fetch TiDB list: ', err as Error)
          }
        }
      }
    )

    const clusters = useMemo(() => {
      if (!data?.tidbs) return []
      return data.tidbs.map(getBFFTiDB).filter((c) => {
        if (!search) return true
        return c.displayName.toLowerCase().includes(search.toLowerCase())
      })
    }, [data?.tidbs, search])

    useEffect(() => {
      if (isProjectSelected) {
        open()
      }
    }, [isProjectSelected, open])

    useEffect(() => {
      if (!currentTidbId || !opened || isLoading) return

      const selectedClusterEl = document.querySelector<HTMLElement>(
        `[data-nav-switcher-cluster-id="${escapeDomValue(currentTidbId)}"]`
      )
      selectedClusterEl?.scrollIntoView({ block: 'nearest' })
    }, [clusters.length, currentTidbId, isLoading, opened])

    return (
      <>
        <Group key={project.id} gap={4} justify="space-between" wrap="nowrap">
          <Combobox.Option
            sx={{
              flexGrow: 1
            }}
            value={project.id}
            data-nav-switcher-project-id={project.id}
            onClick={async (e) => {
              e.stopPropagation()
              eventTracking('Project Changed', {
                source: 'Global Side Navbar Switcher NextGen - Cluster Panel',
                isOtherOrgSwitch
              })
              onNavigation(project.id)
              projectSwitch(org, project)
            }}
          >
            <Group gap="xs" justify="space-between" wrap="nowrap">
              <Group gap={8} wrap="nowrap">
                <ActionIcon
                  variant="subtle"
                  color="gray"
                  size="md"
                  my={-8}
                  mx={-4}
                  sx={{ flexShrink: 0 }}
                  onClick={async (e) => {
                    e.stopPropagation()
                    toggle()
                    if (opened) {
                      eventTracking('Collapse project', {
                        source: 'Global Side Navbar Switcher NextGen'
                      })
                    } else {
                      eventTracking('Expand project', {
                        source: 'Global Side Navbar Switcher NextGen'
                      })
                    }
                  }}
                >
                  {opened ? <IconChevronDown /> : <IconChevronRight />}
                </ActionIcon>
                {project.type !== ProjectType.TIDBX_VIRTUAL && (
                  <Group>
                    {project.type === ProjectType.DEDICATED ? (
                      <IconDProjectFill size={16} c="carbon.8" />
                    ) : (
                      <IconFolder size={16} c="carbon.8" strokeWidth={1} />
                    )}
                  </Group>
                )}
                <Highlight highlight={search}>{project.name || `Project (ID: ${project.id})`}</Highlight>
              </Group>
              <Group gap={8} wrap="nowrap">
                {isProjectSelected && <IconCheck c="peacock.7" />}
              </Group>
            </Group>
          </Combobox.Option>
          {project.type === ProjectType.DEDICATED && (
            <ActionIcon
              variant="subtle"
              size="md"
              my={-8}
              w={32}
              h={32}
              sx={{
                flexShrink: 0
              }}
              onClick={async (e) => {
                e.stopPropagation()
                eventTracking('Click project settings', {
                  source: 'Global Side Navbar Switcher NextGen - Cluster Panel'
                })
                onNavigation(project.id)
                await projectSwitch(org, project)
                history.push(PROJECT_SETTINGS_PATH)
              }}
            >
              <IconSettings02 size={16} c="carbon.7" />
            </ActionIcon>
          )}
        </Group>
        {opened && (
          <>
            {isLoading ? (
              <Stack pl={62} gap={0}>
                {Array.from({ length: 3 }).map((_, index) => (
                  <Flex key={`skeleton-${index}`} h={34} align="center">
                    <Skeleton height={16} radius="md" w={'calc(100% - 36px)'} />
                  </Flex>
                ))}
              </Stack>
            ) : clusters.length === 0 ? (
              <Typography variant="body-lg" c="carbon.7" px={12} pl={62}>
                {project.type === ProjectType.DEDICATED ? 'No cluster yet' : 'No instance yet'}
              </Typography>
            ) : (
              <>
                {clusters.map((cluster) => {
                  const isSelected = (currentTidbId || tidb?.tidbId) === cluster.tidbId
                  return (
                    <Combobox.Option
                      pl={62}
                      key={cluster.tidbId}
                      value={cluster.tidbId!}
                      data-nav-switcher-cluster-id={cluster.tidbId}
                      onClick={async (e) => {
                        e.stopPropagation()
                        eventTracking('Cluster Changed', {
                          source: 'Global Side Navbar Switcher NextGen - Cluster Panel'
                        })
                        onNavigation(cluster.tidbId!)
                        updateLastVisitLocation({ projectId: cluster.projectId })
                        clusterSwitch(org, cluster)
                      }}
                      sx={{
                        wordBreak: 'break-all'
                      }}
                    >
                      <Group gap="xs" justify="space-between" wrap="nowrap">
                        <Group gap="xs" wrap="nowrap">
                          {cluster.servicePlan && <ServicePlanTag servicePlan={cluster.servicePlan} size="xs" />}
                          <Highlight highlight={search}>
                            {cluster.displayName || `Instance (ID: ${cluster.tidbId})`}
                          </Highlight>
                        </Group>
                        <Group w={32} justify="flex-end">
                          {isSelected && <IconCheck c="peacock.7" />}
                        </Group>
                      </Group>
                    </Combobox.Option>
                  )
                })}
                {data?.totalSize && data.totalSize > CLUSTER_NUM_PER_PAGE && (
                  <Typography variant="body-sm" c="carbon.7" px={12} pl={62}>
                    more instance please use filter
                  </Typography>
                )}
              </>
            )}
          </>
        )}
      </>
    )
  }
)
