import { Card, Button, Group, Stack, Typography, Tooltip, Box, TypographyProps, notifier, Flex } from '@tidbcloud/uikit'
import { useMemoizedFn } from 'ahooks'
import { observer } from 'mobx-react'
import { useState } from 'react'
import { useFormContext } from 'react-hook-form'
import { useQueryClient } from 'react-query'
import { useHistory } from 'react-router-dom'

import { PropertyKV } from 'dbaas/components'
import { AccessGuard } from 'dbaas/contexts/access-control'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { CloudProviderLabelConst } from 'dbaas/features/Project'
import { useAddCreditCard } from 'dbaas/screens/ClustersV2/new/Serverless/helpers'
import { PaymentMethodModal } from 'dbaas/screens/Stripe'
import { getGetSpendLimitDetailsQueryKey, getSpendLimitDetails } from 'dbaas/services/api'
import { useModifySpendLimit } from 'dbaas/services/api-clients/legacy/serverless'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { toCents } from 'dbaas/utils/format'
import { moneyFormatter } from 'dbaas/utils/numberFormat'

import { EditFormValueState, useCancel } from './helpers'
interface SumInfoItemProps {
  label: string
  value?: React.ReactNode
  isError?: boolean
  errors?: React.ReactNode
  labelProps?: TypographyProps
}

export const SumInfoItem = ({ label, value = '', isError, errors, labelProps = {} }: SumInfoItemProps) => {
  return (
    <PropertyKV
      label={label}
      labelProps={{
        w: 112,
        ...labelProps
      }}
      valueProps={{ color: isError ? 'red' : 'carbon.8' }}
    >
      {isError ? (errors ?? `Invalid ${label}`) : value}
    </PropertyKV>
  )
}

const SpendingLimitCost = ({ value = 0 }: { value?: number }) => {
  return (
    <Stack gap={4} py="xl">
      <Group gap={8}>
        <Typography variant="headline-md" c="carbon.9">
          {moneyFormatter(value)}
        </Typography>
        <Typography variant="body-lg">maximum/month</Typography>
      </Group>
      <Typography variant="body-lg">
        {value ? 'No upfront charges. Pay only for your actual usage.' : 'No credit card required.'}
      </Typography>
    </Stack>
  )
}

interface SumCardProps {
  cluster: SharedCluster
}

export const SumCard = observer(({ cluster }: SumCardProps) => {
  const {
    store: {
      lastVisitLocation: { orgId }
    }
  } = useStores()
  const cancel = useCancel()
  const history = useHistory()
  const queryClient = useQueryClient()

  const {
    watch,
    handleSubmit,

    formState: { errors }
  } = useFormContext<EditFormValueState>()
  const { monthlySpendingLimit } = watch()
  const [isWaitingSpendLimitDetail, setIsWaitingSpendLimitDetail] = useState(false)

  const updator = useModifySpendLimit({
    mutation: {
      onError: (error) => {
        const errorMsg = getErrorMessage(error)

        notifier.error(<div dangerouslySetInnerHTML={{ __html: errorMsg }}></div>)
      }
    }
  })
  const onSubmit = useMemoizedFn(async (data: EditFormValueState) => {
    if (!orgId || !cluster?.id) {
      notifier.error(<div dangerouslySetInnerHTML={{ __html: 'Failed to update Spending Limit' }}></div>)

      return
    }

    try {
      setIsWaitingSpendLimitDetail(true)
      const submittedSpendLimit = toCents(data.monthlySpendingLimit)
      const currentSpendLimitDetail = await queryClient.fetchQuery(
        getGetSpendLimitDetailsQueryKey(orgId, cluster.id),
        () => getSpendLimitDetails(orgId, cluster.id)
      )
      const initialSpendLimit = currentSpendLimitDetail?.spend_limit

      if (typeof initialSpendLimit !== 'number' || typeof monthlySpendingLimit !== 'number') {
        notifier.error('Failed to validate the current spending limit. Please refresh and try again.')

        return
      }

      await updator.mutateAsync({
        orgId,
        clusterId: cluster.id,
        data: {
          spend_limit: submittedSpendLimit,
          region: cluster.region
        }
      })

      if (submittedSpendLimit !== initialSpendLimit) {
        let isUpdated = false

        for (let attempt = 0; attempt < 5; attempt++) {
          const detailResult = await queryClient.fetchQuery(getGetSpendLimitDetailsQueryKey(orgId, cluster.id), () =>
            getSpendLimitDetails(orgId, cluster.id)
          )

          if (detailResult?.spend_limit !== initialSpendLimit) {
            isUpdated = true
            break
          }

          if (attempt < 4) {
            await new Promise((resolve) => window.setTimeout(resolve, 1000))
          }
        }

        if (!isUpdated) {
          notifier.error('Configuration has not taken effect yet. Please refresh and try again.')

          return
        }
      }
    } finally {
      setIsWaitingSpendLimitDetail(false)
    }

    history.push(`/clusters/${cluster.id}/overview`)
    notifier.success('Spending limit updated successfully!')
  })
  const onConfirm = handleSubmit(onSubmit)

  const { creditAddVisible, creditModalVisible, creditModalHandlers } = useAddCreditCard(monthlySpendingLimit)

  return (
    <Card shadow="none" p="xl" miw={400}>
      <Typography variant="title-lg">Summary</Typography>
      <Typography variant="body-lg" c="carbon.7" mt={4}>
        Your new instance will be
      </Typography>
      <Stack justify="flex-start" gap={8} pt="xl">
        <SumInfoItem label="Plan" value="TiDB Cloud Starter" />
        <SumInfoItem label="Provider" value={CloudProviderLabelConst[cluster.provider]} />
        <SumInfoItem label="Region" value={cluster.regionDisplayName} />
        <SumInfoItem label="Name" value={cluster?.displayName} />
        <SumInfoItem
          label="Spending Limit"
          value={`$${monthlySpendingLimit} / month`}
          isError={!!errors?.monthlySpendingLimit}
        />
      </Stack>
      <SpendingLimitCost value={monthlySpendingLimit} />
      <Flex align="center" gap="md">
        <Button variant="default" onClick={cancel} data-mp-event="Cancel Update Spending Limit Button Clicked">
          Cancel
        </Button>
        {!creditAddVisible && (
          <Button
            disabled={!monthlySpendingLimit}
            loading={updator.isLoading || isWaitingSpendLimitDetail}
            onClick={onConfirm}
            sx={{ flexGrow: 1 }}
            data-mp-event="Update Spending Limit Button Clicked"
          >
            Update Spending Limit
          </Button>
        )}
        {creditAddVisible && (
          <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 data-mp-event="mp-addcreditcard-1691461017865">
                    Add Credit Card
                  </Button>
                </Box>
              </Tooltip>
            }
          >
            <Button
              disabled={!orgId || !cluster?.id || !!errors?.monthlySpendingLimit}
              onClick={creditModalHandlers.open}
              sx={{ flexGrow: 1 }}
              data-mp-event="Add Credit Card and Update Cluster Plan Button Clicked"
            >
              Add Credit Card
            </Button>
          </AccessGuard>
        )}
      </Flex>
      {creditAddVisible && (
        <PaymentMethodModal
          open={creditModalVisible}
          onClose={creditModalHandlers.close}
          onComplete={() => {
            creditModalHandlers.close()
            onConfirm()
            notifier.success('Your credit card is added successfully!')
          }}
        />
      )}
    </Card>
  )
})
