import {
  AnimatedNumber,
  Alert,
  Box,
  Button,
  Collapse,
  Divider,
  Flex,
  Group,
  Skeleton,
  Stack,
  Tooltip,
  Typography,
  notifier
} from '@tidbcloud/uikit'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconChevronDown, IconChevronUp } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useMemo } from 'react'
import { useFormContext } from 'react-hook-form'
import { useHistory, useLocation } from 'react-router-dom'

import { PropertyKV } from 'dbaas/components'
import { AccessGuard } from 'dbaas/contexts/access-control'
import { renderNodes, renderStorage } from 'dbaas/features/ClusterManagement/common'
import { renderTiproxy } from 'dbaas/features/ClusterManagement/dedicated/node/NodeSizes/TiProxy'
import { WaringForSpecInSummary } from 'dbaas/features/ClusterManagement/dedicated/node/NodeSizes/WarningForSpecInSummary'
import { CloudProviderConst, getCloudProviderLabel } from 'dbaas/features/Project'
import { renderSpecVersion, useSpecVersionEnabled } from 'dbaas/screens/Cluster/OverviewV2/helpers'
import { CostDetail } from 'dbaas/screens/ClustersV2/new/Dedicated/SumCard/CostPanel/CostDetail'
import { renderStorageType } from 'dbaas/screens/ClustersV2/new/helpers'
import { useCreationStore } from 'dbaas/screens/ClustersV2/new/store'
import { NodeSpecByType } from 'dbaas/screens/ClustersV2/new/store/helpers'
import { useAddCreditCard } from 'dbaas/screens/NextGen/my-tidb-creation/shared/use-add-credit-card'
import { PaymentMethodModal } from 'dbaas/screens/Stripe'
import { EstimatePriceResponsePrice } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta1/interface'
import { Dedicatedv1beta1ComponentType } from 'dbaas/services/api-clients/v2023/dedicated/v1beta1/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

import { getDedicatedProjectName } from './dedicated-project'
import { useDedicatedCosts } from './hooks/use-dedicated-costs'
import { DedicatedCreationFormValue } from './types'

export const NodeSizeSkeleton = () => (
  <Stack justify="flex-start" gap={8}>
    <Skeleton width={140} height={16} />
    <Skeleton width={80} height={16} />
  </Stack>
)

const SumInfoItem = ({ label, value, isError }: { label: string; value: React.ReactNode; isError?: boolean }) => {
  return (
    <PropertyKV label={label} labelProps={{ w: 144 }} valueProps={{ c: isError ? 'red' : undefined }}>
      {value}
    </PropertyKV>
  )
}

const useNodeProfileTargets = ({
  tidbProfileName,
  tikvProfileName,
  tiflashProfileName,
  nodeProfiles
}: {
  tidbProfileName?: string
  tikvProfileName?: string
  tiflashProfileName?: string
  nodeProfiles?: NodeSpecByType[]
}) => {
  return useMemo(() => {
    const [tidb, tikv, tiflash] = [
      {
        type: Dedicatedv1beta1ComponentType.TIDB,
        profileName: tidbProfileName
      },
      {
        type: Dedicatedv1beta1ComponentType.TIKV,
        profileName: tikvProfileName
      },
      {
        type: Dedicatedv1beta1ComponentType.TIFLASH,
        profileName: tiflashProfileName
      }
    ].map(({ type, profileName }) => {
      const profiles = nodeProfiles?.find((item) => item.componentType === type)?.nodeSpecs
      const profile = profiles?.find((item) => item.name === profileName)
      const label = profile?.displayName ?? ''
      const version = profile?.version ?? ''

      return {
        profile,
        label,
        version
      }
    })

    return {
      tidb,
      tikv,
      tiflash
    }
  }, [tidbProfileName, tiflashProfileName, tikvProfileName, nodeProfiles])
}

const NewClusterPricingSummary = ({
  error,
  totalCost,
  costsDetail
}: {
  error?: string
  totalCost: number
  costsDetail: EstimatePriceResponsePrice[]
}) => {
  const [costDetailVisible, costDetailHandlers] = useDisclosure(false)

  return (
    <Stack gap={4} mt="sm">
      <Group onClick={costDetailHandlers.toggle} sx={{ '&:hover': { cursor: error ? 'auto' : 'pointer' } }}>
        {error ? (
          <Group gap="xs">
            <Typography variant="headline-md">-</Typography>
            <Typography variant="body-lg">/hour</Typography>
          </Group>
        ) : (
          <AnimatedNumber
            value={error ? 0 : totalCost}
            format={{ maximumFractionDigits: 5, minimumFractionDigits: 2 }}
            prefix="$"
            suffix="/hour"
            c="carbon.9"
            fw={700}
            fz={20}
            sx={{
              '&::part(suffix)': {
                color: 'var(--mantine-color-carbon-8)',
                fontWeight: 400,
                fontSize: 14
              }
            }}
          />
        )}
        {!error && <Box component={costDetailVisible ? IconChevronUp : IconChevronDown} size={14} />}
      </Group>
      <Collapse in={!error && costDetailVisible}>
        <CostDetail costs={costsDetail} />
      </Collapse>

      <Typography variant="body-lg" c="carbon.7">
        You will be billed hourly and can terminate your cluster anytime. Learn more in{' '}
        <a href="https://www.pingcap.com/tidb-cloud-pricing-details/#node-cost" target="_blank" rel="noreferrer">
          Pricing Details
        </a>
        .
      </Typography>

      {error && <Alert color="red">{error}</Alert>}
    </Stack>
  )
}

interface DedicatedSummaryProps {
  formId: string
  isPending?: boolean
}

export const DedicatedSummary = observer(({ formId, isPending }: DedicatedSummaryProps) => {
  const history = useHistory()
  const location = useLocation()
  const {
    store: {
      lastVisitLocation: { orgId, projectId },
      userProfile: { projects: allProjects }
    }
  } = useStores()

  const { dedicated: store } = useCreationStore()
  const cidrConfiguredStatus = store?.cidrConfigured
  const cidrConfigured = cidrConfiguredStatus === true

  const {
    watch,
    formState: { dirtyFields, errors }
  } = useFormContext<DedicatedCreationFormValue>()

  const formErrors = errors.dedicated
  const formDirtyFields = dirtyFields.dedicated

  const { dedicated: initializing } = watch('initializing')
  const provider = watch('dedicated.provider')
  const region = watch('dedicated.region')
  const name = watch('dedicated.name')
  const port = watch('dedicated.port')
  const sizes = watch('dedicated.sizes')
  const projectCIDR = watch('dedicated.projectCIDR')

  const projectName = getDedicatedProjectName(allProjects, projectId)

  const { regionName } = useMemo(() => {
    const targetRegion = store?.providers.find((p) => p.name === provider)?.regions.find((r) => r.name === region)

    return {
      regionName: targetRegion?.display_name ?? ''
    }
  }, [provider, region, store?.providers])

  const profileTargets = useNodeProfileTargets({
    tidbProfileName: sizes?.tidb?.profileName,
    tikvProfileName: sizes?.tikv?.profileName,
    tiflashProfileName: sizes?.tiflash?.profileName,
    nodeProfiles: store?.nodeProfiles
  })

  const isError = !!formErrors?.provider || !!formErrors?.region || !!formErrors?.sizes

  const {
    costs,
    totalCost,
    isLoading: isCostLoading,
    error: costError
  } = useDedicatedCosts({
    orgId,
    projectId,
    provider,
    region,
    sizes,
    enabled: !isError && !!provider && !!region && !!sizes
  })

  const { creditCardNeeded, creditCardModalVisible, creditCardModalHandlers } = useAddCreditCard()

  const loading = JSON.parse(initializing) as boolean

  const { specVersionEnabled } = useSpecVersionEnabled(provider)

  const filledFields = ['provider', 'region', 'name'].filter((key) => formDirtyFields?.[key]).join(', ')

  const cidrStatusLoading = !!provider && !!region && typeof cidrConfiguredStatus === 'undefined'
  const submitDisabled = loading || isCostLoading || !!isPending || cidrStatusLoading

  return (
    <Box sx={{ display: 'flex', flexDirection: 'column', height: '100%', minHeight: 0 }}>
      <Box>
        <Typography variant="title-lg">Summary</Typography>
        <Typography variant="body-lg" c="carbon.7" mt={4}>
          Your new cluster will be:
        </Typography>

        <Stack justify="flex-start" gap={8} pt="xl" pb="md" sx={{ position: 'relative' }}>
          <SumInfoItem label="Plan" value="Dedicated" />
          <SumInfoItem label="Project" value={projectName} />
          <SumInfoItem
            label="Cluster Name"
            value={loading ? <Skeleton width={100} height={16} /> : name || '-'}
            isError={!!formErrors?.name}
          />
          <SumInfoItem
            label="Cloud Provider"
            value={loading ? <Skeleton width={80} height={16} /> : getCloudProviderLabel(provider)}
          />
          <SumInfoItem label="Region" value={loading ? <Skeleton width={150} height={16} /> : regionName} />
        </Stack>
        <Divider />
        <Stack justify="flex-start" gap={8} py="md" sx={{ position: 'relative' }}>
          <SumInfoItem
            label="TiDB"
            value={
              loading ? (
                <NodeSizeSkeleton />
              ) : (
                <Stack justify="flex-start" gap={8}>
                  <Group gap={4}>
                    {profileTargets.tidb.label}
                    {renderSpecVersion(profileTargets.tidb.version, specVersionEnabled)}
                    <WaringForSpecInSummary
                      cpuNum={profileTargets.tidb.profile?.vCpu ?? 0}
                      memory={profileTargets.tidb.profile?.memorySizeGi ?? 0}
                    />
                  </Group>
                  <Box>Default Group x {renderNodes(sizes?.tidb?.replicas)}</Box>
                  {renderTiproxy(sizes?.tidb.tiproxySetting)}
                </Stack>
              )
            }
            isError={!!formErrors?.sizes?.tidb}
          />
          <SumInfoItem
            label="TiKV"
            value={
              loading ? (
                <NodeSizeSkeleton />
              ) : (
                <Stack justify="flex-start" gap={8}>
                  <Group gap={4}>
                    {profileTargets.tikv.label}
                    {renderSpecVersion(profileTargets.tikv.version, specVersionEnabled)}
                    <WaringForSpecInSummary
                      cpuNum={profileTargets.tikv.profile?.vCpu ?? 0}
                      memory={profileTargets.tikv.profile?.memorySizeGi ?? 0}
                    />
                  </Group>
                  <Box>
                    {sizes?.tikv?.storageGiB || 0} GiB Storage × {renderNodes(sizes?.tikv?.replicas)}
                  </Box>
                  {sizes?.tikv.storageType && <Box>{renderStorageType(sizes?.tikv.storageType)} Storage</Box>}
                  {sizes?.tikv.raftStoreIops && <Box>{sizes.tikv.raftStoreIops} Extra Raft IOPS</Box>}
                  {sizes?.tikv.storageType === 'Plus' && sizes.tikv.dataStoreIops && (
                    <Box>{sizes.tikv.dataStoreIops.toLocaleString()} Data Disk IOPS</Box>
                  )}
                </Stack>
              )
            }
            isError={!!formErrors?.sizes?.tikv}
          />
          {!!sizes?.tiflash?.replicas && (
            <SumInfoItem
              label="TiFlash"
              value={
                loading ? (
                  <NodeSizeSkeleton />
                ) : (
                  <Stack justify="flex-start" gap={8}>
                    <Group>
                      {profileTargets.tiflash.label}
                      {renderSpecVersion(profileTargets.tiflash.version, specVersionEnabled)}
                      <WaringForSpecInSummary
                        cpuNum={profileTargets.tiflash.profile?.vCpu ?? 0}
                        memory={profileTargets.tiflash.profile?.memorySizeGi ?? 0}
                      />
                    </Group>
                    <Box>
                      {renderStorage(sizes?.tiflash?.storageGiB)} × {renderNodes(sizes?.tiflash?.replicas)}
                    </Box>
                    {provider === CloudProviderConst.AWS && (
                      <Box>{renderStorageType(sizes?.tiflash.storageType)} Storage</Box>
                    )}
                  </Stack>
                )
              }
              isError={!!formErrors?.sizes?.tiflash}
            />
          )}
        </Stack>
        <Divider />
        <Stack justify="flex-start" gap={8} py="md" sx={{ position: 'relative' }}>
          <SumInfoItem label="Port" value={port} isError={!!formErrors?.port} />
          {!cidrConfigured && (
            <SumInfoItem label="CIDR" value={projectCIDR || '-'} isError={!!formErrors?.projectCIDR} />
          )}
        </Stack>
      </Box>

      <Divider />

      <Box sx={{ marginTop: 'auto' }}>
        <NewClusterPricingSummary
          error={getErrorMessage(costError, true)}
          totalCost={totalCost ?? 0}
          costsDetail={costs}
        />

        <Flex align="center" gap="md" mt="md">
          <Button
            variant="default"
            onClick={() => history.push(`/tidbs${location.search}`)}
            data-mp-event="Cancel Created A Cluster"
            data-mp-service-plan="Dedicated"
            data-mp-source="Clusters - Creation v2"
            data-mp-filled-fields={filledFields}
          >
            Cancel
          </Button>

          <AccessGuard
            id="ClusterCreationGate"
            fallback={
              <Tooltip
                sx={{ flexGrow: 1 }}
                label="Please ask your admin to grant you the permission to create a Dedicated cluster."
              >
                <Box sx={{ flexGrow: 1 }}>
                  <Button disabled sx={{ width: '100%' }}>
                    Create
                  </Button>
                </Box>
              </Tooltip>
            }
          >
            {creditCardNeeded ? (
              <AccessGuard
                id="BillingPaymentCreation"
                fallback={
                  <Tooltip
                    sx={{ flexGrow: 1 }}
                    label="Please contact the Owner or Billing Manager to add a credit card and your discount will be applied to your next billing cycle."
                  >
                    <Box>
                      <Button
                        disabled
                        loading={isCostLoading || loading}
                        data-mp-event="mp-addcreditcard-1691461017800"
                      >
                        {isCostLoading ? 'Calculating...' : loading ? 'Fetching...' : `Add Credit Card`}
                      </Button>
                    </Box>
                  </Tooltip>
                }
              >
                <Button
                  loading={isCostLoading || loading}
                  onClick={creditCardModalHandlers.open}
                  sx={{ flexGrow: 1 }}
                  data-mp-event="Add Credit Card Button Clicked"
                  data-mp-service-plan="Dedicated"
                  data-mp-source="Clusters - Creation v2"
                >
                  {isCostLoading ? 'Calculating...' : loading ? 'Fetching...' : `Add Credit Card`}
                </Button>
              </AccessGuard>
            ) : (
              <Button
                type="submit"
                form={formId}
                disabled={submitDisabled}
                loading={!!isPending}
                sx={{ flexGrow: 1 }}
                data-mp-event="Cluster Creation Button Clicked"
                data-mp-service-plan="Dedicated"
                data-mp-source="Clusters - Creation v2"
                data-testid="dedicated-cluster-creation-btn"
              >
                {isCostLoading ? 'Calculating...' : loading || cidrStatusLoading ? 'Fetching...' : 'Create'}
              </Button>
            )}
          </AccessGuard>
        </Flex>

        {creditCardNeeded && (
          <PaymentMethodModal
            open={creditCardModalVisible}
            onClose={creditCardModalHandlers.close}
            onComplete={() => {
              notifier.success('Your credit card has been saved successfully.')
              creditCardModalHandlers.close()
            }}
          />
        )}
      </Box>
    </Box>
  )
})
