import { Box, Group, Button, LoadingOverlay, Alert, Grid, Card, Typography, Flex, Modal } from '@tidbcloud/uikit'
import { isString } from 'lodash-es'
import { useState } from 'react'
import { useQueryClient } from 'react-query'

import { ModalCodeTitle } from 'dbaas/components'
import { useAccessCheck } from 'dbaas/contexts/access-control'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { ClusterNodes, useNewApiFetchClusterCost } from 'dbaas/features/ClusterManagement/dedicated'
import {
  getClusterServiceGetClusterQueryKey,
  useClusterServiceGetCluster
} from 'dbaas/services/api-clients/v2023/cluster-management/v1beta1'
import {
  useClusterServicePauseCluster,
  useClusterServiceResumeCluster
} from 'dbaas/services/api-clients/v2023/dedicated/v1beta1'
import useStores from 'dbaas/stores/useStores'

import { pauseDescriptions, resumeDescriptions } from './data'

const showDescriptions = (
  descriptions: (
    | string
    | {
        text: string
        children: string[]
      }
  )[]
) => {
  return descriptions.map((line, index) =>
    isString(line) ? (
      <Typography key={index} variant="label-lg" sx={() => ({ height: 42 })}>
        {line}
      </Typography>
    ) : (
      <Box key={index}>
        <Typography variant="label-lg" sx={() => ({ height: 42 })}>
          {line.text}
        </Typography>
        {line.children.map((child, idx) => (
          <Typography key={idx} variant="body-lg" sx={() => ({ height: 42 })}>
            {child}
          </Typography>
        ))}
      </Box>
    )
  )
}

export interface PauseOrResumeClusterProps {
  /**
   * Cluster ID.
   */
  id: string

  /**
   * Actually the `cluster` prop is required.
   */
  cluster?: Pick<SharedCluster, 'id' | 'displayName' | 'computed'>

  /**
   * @deprecated Don't use it anymore. Use `visible` instead
   */
  trigger?: React.ReactNode

  /**
   * Whether the modal is opened.
   * If not provided, the modal can't be opened.
   */
  visible?: boolean

  /**
   * Whether to use the new API.
   * Default to `true`.
   */
  useNewApi?: boolean

  /**
   * Callback to close the modal.
   * If not provided, the modal can't be closed!
   */
  onClose?: () => void

  /**
   * Call when the operation is finished.
   */
  onFinish?: () => Promise<unknown> | void
}

function PauseOrResumeCluster({ id: clusterId, cluster, visible, onClose, onFinish }: PauseOrResumeClusterProps) {
  const queryClient = useQueryClient()
  const {
    store: {
      lastVisitLocation: { orgId, projectId }
    }
  } = useStores()
  const { displayName: clusterName, computed } = cluster || {}
  const isPaused = computed?.paused
  const pauseOrResume = computed?.paused ? 'Resume' : 'Pause'
  const pausedOrResumed = computed?.paused ? 'resumed' : 'paused'

  const [error, setError] = useState('')
  const closeModal = () => {
    setError('')
    onClose?.()
  }

  const newPauseMutator = useClusterServicePauseCluster({
    mutation: {
      onError: (error) => {
        setError(error.message || '')
      }
    }
  })
  const newResumeMutator = useClusterServiceResumeCluster({
    mutation: {
      onError: (error) => {
        setError(error.message || '')
      }
    }
  })

  const handlePauseOrResumeClusterWithNewApi = async () => {
    isPaused
      ? await newResumeMutator.mutateAsync({
          clusterId,
          params: { orgId, projectId }
        })
      : await newPauseMutator.mutateAsync({
          clusterId,
          params: { orgId, projectId }
        })

    queryClient.invalidateQueries({
      queryKey: getClusterServiceGetClusterQueryKey(clusterId, {
        orgId,
        projectId
      }),
      refetchInactive: true
    })
    // @TODO: Do we need to wait for `onFinish` callback?
    onFinish?.()
    closeModal()
  }

  const clusterQuery = useClusterServiceGetCluster(
    clusterId,
    {
      orgId,
      projectId
    },
    {
      query: {
        enabled: !!(visible && clusterId && orgId && projectId),
        select: (data) => data?.dedicatedCluster,
        refetchOnWindowFocus: false,
        refetchOnMount: false
      }
    }
  )
  const { cloudProvider = '', regionId = '' } = clusterQuery.data || {}
  const region = regionId.replace(/^(aws|gcp|azure)-/, '')

  const nodes: ClusterNodes = {
    tidb: {
      specKey: clusterQuery.data?.tidbNodeSetting?.nodeSpecKey || '',
      nodeGroups: clusterQuery.data?.tidbNodeSetting?.tidbNodeGroups || []
    },
    tikv: {
      specKey: clusterQuery.data?.tikvNodeSetting?.nodeSpecKey || '',
      nodeCount: clusterQuery.data?.tikvNodeSetting?.nodeCount || 0,
      storageGiB: clusterQuery.data?.tikvNodeSetting?.storageSizeGi || 0,
      storageType: clusterQuery.data?.tikvNodeSetting?.storageType,
      raftStoreIops: clusterQuery.data?.tikvNodeSetting?.raftStoreIops || 0
    },
    tiflash: {
      specKey: clusterQuery.data?.tiflashNodeSetting?.nodeSpecKey || '',
      nodeCount: clusterQuery.data?.tiflashNodeSetting?.nodeCount || 0,
      storageGiB: clusterQuery.data?.tiflashNodeSetting?.storageSizeGi || 0,
      storageType: clusterQuery.data?.tiflashNodeSetting?.storageType
    }
  }

  const { query: newApiActiveCostQuery } = useNewApiFetchClusterCost(
    {
      clusterId,
      provider: cloudProvider,
      region,
      paused: false,
      nodes
    },
    {
      query: {
        enabled: !!visible
      }
    }
  )

  const { query: newApiPausedCostQuery } = useNewApiFetchClusterCost(
    {
      clusterId,
      provider: cloudProvider,
      region,
      paused: true,
      nodes
    },
    {
      query: {
        enabled: !!visible
      }
    }
  )

  const pausedPrice = newApiPausedCostQuery.data?.total

  const normalPrice = newApiActiveCostQuery.data?.total

  const accessible = useAccessCheck('ClusterPause')

  if (!accessible) {
    return null
  }

  return (
    <Modal
      size="xl"
      centered
      opened={!!visible}
      title={
        <Box data-testid="clusterStatus">
          {pauseOrResume} <ModalCodeTitle maxWidth={400}>{clusterName}</ModalCodeTitle> cluster
        </Box>
      }
      onClose={closeModal}
    >
      <Grid columns={2} mb={20}>
        <Grid.Col span={1}>
          <Card sx={(theme) => ({ background: theme.colors.carbon[3] })}>
            <Flex align="center" h={80}>
              <Typography mr={5} variant="body-lg">
                {isPaused ? 'Paused cluster cost' : 'Available cluster cost'}
              </Typography>
              <Typography variant="headline-lg">$ {isPaused ? pausedPrice : normalPrice} /Hour</Typography>
            </Flex>
          </Card>
        </Grid.Col>
        <Grid.Col span={1}>
          <Card sx={(theme) => ({ background: theme.colors.blue[2] })}>
            <Flex align="center" h={80}>
              <Typography mr={5} variant="body-lg">
                {isPaused ? 'Available cluster cost' : 'Paused cluster cost'}
              </Typography>
              <Typography variant="headline-lg">$ {isPaused ? normalPrice : pausedPrice} /Hour</Typography>
            </Flex>
          </Card>
        </Grid.Col>
      </Grid>

      <Typography variant="headline-sm" mb={20}>{`When your TiDB cluster is ${pausedOrResumed}`}</Typography>

      {/* Descriptions */}
      {showDescriptions(isPaused ? resumeDescriptions : pauseDescriptions)}

      {/* Error message */}
      {error && (
        <Alert color="red" mb={20}>
          <p dangerouslySetInnerHTML={{ __html: error }} />
        </Alert>
      )}

      <LoadingOverlay visible={newApiActiveCostQuery.isLoading || newApiPausedCostQuery.isLoading} />
      <Group justify="flex-end">
        <Button
          variant="default"
          disabled={newPauseMutator.isLoading || newResumeMutator.isLoading}
          onClick={closeModal}
          data-mp-event="PauseOrResume Cluster Cancel Button Clicked"
          data-mp-type={pauseOrResume}
        >
          Cancel
        </Button>
        <Button
          loading={newPauseMutator.isLoading || newResumeMutator.isLoading}
          onClick={handlePauseOrResumeClusterWithNewApi}
          data-mp-event="PauseOrResume Cluster Confirm Button Clicked"
          data-mp-type={pauseOrResume}
          data-testid="PauseOrResumeButton"
        >
          {pauseOrResume}
        </Button>
      </Group>
    </Modal>
  )
}

export default PauseOrResumeCluster
