import {
  Accordion,
  Box,
  Button,
  Card,
  Divider,
  Group,
  Loader,
  notifier,
  SegmentedControl,
  Stack,
  Tooltip,
  Typography
} from '@tidbcloud/uikit'
import { DateTimePicker, FormErrorMessage, FormRadioGroup, FormSelect, FormTextInput } from '@tidbcloud/uikit/biz'
import { useMemoizedFn } from 'ahooks'
import { observer } from 'mobx-react'
import { useMemo, useState } from 'react'
import { Controller, FormProvider, useForm } from 'react-hook-form'
import { Link, useHistory } from 'react-router-dom'

import { AccessGuard } from 'dbaas/contexts/access-control'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { useOrgProjectClusterIds } from 'dbaas/features/Common'
import { CloudProviderLabelConst } from 'dbaas/features/Project'
import HeadLabel from 'dbaas/screens/ClustersV2/new/components/HeadLabel'
import { SumInfoItem } from 'dbaas/screens/ClustersV2/new/components/summary/SumInfoItem'
import { CreationFormValueState } from 'dbaas/screens/ClustersV2/new/helpers/form'
import { AdvancedSettings } from 'dbaas/screens/ClustersV2/new/Serverless/FormContent/AdvancedSettings'
import { StarterCapacityItem } from 'dbaas/screens/ClustersV2/new/Serverless/FormContent/StarterCapacity'
import { useAddCreditCard } from 'dbaas/screens/ClustersV2/new/Serverless/helpers'
import { SpendLimitCost } from 'dbaas/screens/ClustersV2/new/Serverless/SumCard/SpendLimit'
import { ClusterPageShell } from 'dbaas/screens/ClusterV2/components'
import { PaymentMethodModal } from 'dbaas/screens/Stripe'
import { useGetSpendLimitDetails } from 'dbaas/services'
import {
  useBackupRestoreServiceListBackups,
  useBackupRestoreServiceRestore,
  useGetBackupRetention
} from 'dbaas/services/api-clients/legacy/serverless'
import {
  BackupRestoreServiceRestoreBody,
  RestoreTypeEnum as ServerlessRestoreTypeEnum
} from 'dbaas/services/api-clients/legacy/serverless/interface'
import { useServerlessServiceGetCluster } from 'dbaas/services/api-clients/v2023/serverless/v1beta1'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { formatTime, toCents, toDollars } from 'dbaas/utils/format'
import { moneyFormatter } from 'dbaas/utils/numberFormat'
import { clusterNameRules } from 'dbaas/utils/validationRules'

import { getPitrTimeRange } from './getPitrTimeRange'

interface FormData {
  mode: 'pitr' | 'snapshot'
  snapshot_id: string
  pitr_date: Date
  serverless: CreationFormValueState['serverless']
}

/**
 * @deprecated
 * This component is deprecated and will be removed in future releases.
 * Now we use the `RestoreForServerlessNextGen` component for both starter and essential.
 */
export const RestoreForServerless = observer(({ cluster }: { cluster: SharedCluster }) => {
  const {
    store: {
      tenantData,
      currentCluster,
      config: { serverlessAdvancedEnabled }
    },
    actions
  } = useStores()
  const urlParams = new URLSearchParams(window.location.search)
  const history = useHistory()
  const [destinationMode, setDestinationMode] = useState<ServerlessRestoreTypeEnum>(ServerlessRestoreTypeEnum.NEW)
  const methods = useForm<FormData>({
    mode: 'onChange',
    defaultValues: {
      mode: 'snapshot',
      snapshot_id: urlParams.get('backup_id') ?? '',
      pitr_date: undefined,
      serverless: {
        provider: cluster.serverless?.region.cloudProvider,
        region: cluster.serverless?.region.name,
        name: '',
        plan: 'scalable',
        monthlySpendingLimit: 0,
        encrypted: false,
        highAvailabilityType: cluster.serverless?.highAvailabilityType
      }
    }
  })
  const {
    setValue,
    watch,
    handleSubmit,
    formState: { errors }
  } = methods
  const mode = watch('mode')
  const pitrDate = watch('pitr_date')
  const snapshotId = watch('snapshot_id')
  const monthlySpendingLimit = watch('serverless.monthlySpendingLimit')
  const clusterName = watch('serverless.name')

  const { creditAddVisible, creditModalVisible, creditModalHandlers } = useAddCreditCard(monthlySpendingLimit)
  const { orgId, projectId, clusterId } = useOrgProjectClusterIds()

  useServerlessServiceGetCluster(
    clusterId!,
    {
      view: 'BASIC',
      orgId,
      projectId
    },
    {
      query: {
        refetchOnWindowFocus: false,
        onSuccess(data) {
          setValue('serverless.encrypted', data.encryptionConfig?.enhancedEncryptionEnabled ?? false)
        }
      }
    }
  )

  const { data: spendLimitDetails, isLoading: isLoadingSpendLimitDetails } = useGetSpendLimitDetails(
    orgId,
    clusterId!,
    {
      query: {
        refetchOnWindowFocus: false,
        onSuccess(data) {
          if (data.spend_limit > 0) {
            setValue('serverless.plan', 'scalable')
            setValue('serverless.monthlySpendingLimit', toDollars(data.spend_limit))
          }
        }
      }
    }
  )
  const isFreeCluster = (spendLimitDetails?.spend_limit ?? 1) === 0
  const currentSpendLimit = toDollars(spendLimitDetails?.spend_limit ?? 0)

  const modeOptions = [
    { label: 'Snapshot Restore', value: 'snapshot' },
    {
      label: 'Point-in-Time Restore',
      value: 'pitr',
      disabled: isFreeCluster
    }
  ]

  const { data: retentionData, isFetching: isFetchingRetention } = useGetBackupRetention(orgId, projectId, clusterId!, {
    query: {
      enabled: mode === 'pitr',
      refetchOnWindowFocus: false,
      onSuccess(data) {
        const [, endDate] = getPitrTimeRange(currentCluster?.createTime!, data.retention_hours ?? 0)
        if (endDate) {
          setValue('pitr_date', endDate)
        }
      }
    }
  })

  const clusterCreateTime = currentCluster?.createTime!
  const retentionHours = retentionData?.retention_hours ?? 0

  const [startDate, endDate] = useMemo(() => {
    return getPitrTimeRange(clusterCreateTime, retentionHours)
  }, [clusterCreateTime, retentionHours])

  const restore = useBackupRestoreServiceRestore()
  const { data: backupListData, isLoading: isLoadingBackupListData } = useBackupRestoreServiceListBackups(
    orgId,
    projectId,
    clusterId!,
    {
      page_token: '',
      page_size: 100,
      order_by: 'backup_time desc'
    },
    {
      query: {
        refetchOnWindowFocus: false,
        enabled: mode === 'snapshot'
      }
    }
  )
  const snapshotOptions = useMemo(
    () =>
      backupListData?.backups?.map((i) => ({
        label: formatTime(i.backup_time!, {
          offset: tenantData.timezone,
          showSeconds: true,
          showTimezone: true
        }),
        value: i.backup_id!
      })) ?? [],
    [backupListData, tenantData.timezone]
  )

  const disableSubmit = useMemo(() => {
    if (mode === 'pitr') {
      return !pitrDate
    } else if (mode === 'snapshot') {
      return !snapshotId
    }
    return false
  }, [mode, pitrDate, snapshotId])

  const onCancel = useMemoizedFn(() => {
    history.push(`/clusters/${clusterId}/backup`)
  })
  const onSubmit = useMemoizedFn(async (data: FormData) => {
    const payload: BackupRestoreServiceRestoreBody = {
      cluster: {
        high_availability_type: data.serverless.highAvailabilityType,
        display_name: data.serverless.name,
        spending_limit:
          typeof data.serverless.monthlySpendingLimit === 'number'
            ? {
                monthly: toCents(data.serverless.monthlySpendingLimit)
              }
            : undefined
      },
      type: destinationMode
    }

    if (mode === 'snapshot') {
      payload.backup_id = data.snapshot_id
    } else if (mode === 'pitr') {
      payload.point_in_time = {
        cluster_id: clusterId!,
        backup_time: data.pitr_date.toISOString()
      }
    }

    await restore.mutateAsync({ orgId, projectId, data: payload })
    notifier.success('Cluster is restoring...')
    if (destinationMode === ServerlessRestoreTypeEnum.NEW) {
      history.push(`/clusters/`)
    } else {
      actions.fetchCluster(clusterId!)
      history.push(`/clusters/${clusterId}/overview`)
    }
  })

  return (
    <FormProvider {...methods}>
      <ClusterPageShell title="Restore" headerProps={{ withBack: true }}>
        <Box
          component="form"
          onSubmit={handleSubmit(onSubmit)}
          sx={{ height: '100%', display: 'flex', gap: 24, justifyContent: 'center' }}
          data-testid="restore-serverless"
        >
          <Box w={720}>
            <Card withBorder shadow="none" p={0}>
              <Stack p={24}>
                <div>
                  <Typography variant="title-lg">Restore Mode</Typography>
                  <Typography variant="body-lg" c="carbon.7">
                    You can use different mode to select the backup data you want to restore. Point-in-Time restore is
                    currently in beta.
                    {isFreeCluster && (
                      <>
                        {' '}
                        <Link to={`/clusters/${clusterId}/edit-spendlimit`}>Set up spending limit</Link> to use
                        Point-in-Time restore.
                      </>
                    )}
                  </Typography>
                </div>

                <FormRadioGroup name="mode" data={modeOptions} />

                {mode === 'snapshot' && (
                  <FormSelect
                    data={snapshotOptions}
                    name="snapshot_id"
                    placeholder="Select backup snapshot"
                    rules={{ required: 'Required' }}
                    label="Restore from"
                    rightSection={isLoadingBackupListData ? <Loader size="xs" /> : null}
                    disabled={isLoadingBackupListData}
                  />
                )}

                {mode === 'pitr' && (
                  <Controller
                    name="pitr_date"
                    control={methods.control}
                    rules={{ required: 'Required' }}
                    render={({ field }) => (
                      <Stack gap={8}>
                        <Typography variant="label-lg" lh="20px">
                          Restore to
                        </Typography>

                        <DateTimePicker
                          withinPortal
                          formatter={(val) =>
                            formatTime(val, {
                              offset: tenantData.timezone,
                              showSeconds: true,
                              showTimezone: true
                            })
                          }
                          value={field.value}
                          onChange={field.onChange}
                          startDate={startDate}
                          endDate={endDate}
                          loading={isFetchingRetention}
                          disable={isFetchingRetention || (!startDate && !endDate)}
                        />
                      </Stack>
                    )}
                  />
                )}
              </Stack>

              <Divider mx="-24px" />

              <Stack p={24}>
                <div>
                  <Typography variant="title-lg">Destination</Typography>
                  <Typography variant="body-lg" c="carbon.7">
                    Choose where to restore your cluster.
                  </Typography>
                </div>

                <SegmentedControl
                  data={[
                    { label: 'Restore to a New Cluster', value: ServerlessRestoreTypeEnum.NEW },
                    { label: 'In-place Restore', value: ServerlessRestoreTypeEnum.INPLACE }
                  ]}
                  value={destinationMode}
                  onChange={(val) => setDestinationMode(val as any)}
                  maw={360}
                />

                {destinationMode === ServerlessRestoreTypeEnum.INPLACE && (
                  <Typography variant="body-lg">
                    All existing data on the current cluster will be deleted prior to the restore! The cluster will be
                    unavailable for the duration of the restore.
                  </Typography>
                )}
              </Stack>

              {destinationMode === ServerlessRestoreTypeEnum.NEW && (
                <>
                  <Divider mx="-24px" />

                  <Accordion
                    defaultValue={['cluster-settings', 'cluster-name', 'cluster-plan']}
                    variant="contained"
                    multiple
                    styles={() => ({
                      item: {
                        borderColor: 'transparent',
                        borderBottomColor: 'var(--mantine-color-carbon-3)'
                      },
                      control: {
                        padding: 24
                      },
                      content: {
                        padding: 24,
                        paddingTop: 0
                      }
                    })}
                  >
                    <Accordion.Item value="cluster-settings">
                      <Accordion.Control>
                        <HeadLabel
                          label="Cloud Provider & Region"
                          description="Your cluster's cloud provider and region."
                        />
                      </Accordion.Control>
                      <Accordion.Panel>
                        <Stack gap={4}>
                          <Group>
                            <Typography variant="label-lg" miw={100}>
                              Cloud Provider
                            </Typography>
                            <Typography variant="body-md">
                              {CloudProviderLabelConst[cluster.serverless?.region.cloudProvider!]}
                            </Typography>
                          </Group>
                          <Group>
                            <Typography variant="label-lg" miw={100}>
                              Region
                            </Typography>
                            <Typography variant="body-md">{cluster.serverless?.region.displayName}</Typography>
                          </Group>
                        </Stack>
                      </Accordion.Panel>
                    </Accordion.Item>
                    <Accordion.Item value="cluster-name">
                      <Accordion.Control>
                        <HeadLabel label="Cluster Name" description="Set the name of your new cluster." />
                      </Accordion.Control>
                      <Accordion.Panel>
                        <FormTextInput
                          name="serverless.name"
                          rules={clusterNameRules}
                          placeholder="Enter cluster name"
                        />
                      </Accordion.Panel>
                    </Accordion.Item>
                    <Accordion.Item value="cluster-plan">
                      <StarterCapacityItem
                        names={{ plan: 'serverless.plan', spendingLimit: 'serverless.monthlySpendingLimit' }}
                        spendingLimitDescSuffix={
                          isFreeCluster
                            ? undefined
                            : `It is recommended to setting a spending limit greater than or equal to the source cluster's limit of ${moneyFormatter(
                                currentSpendLimit
                              )}`
                        }
                      />
                    </Accordion.Item>

                    {serverlessAdvancedEnabled && (
                      <Accordion.Item value="serverlessAdvanced">
                        <Accordion.Control data-mp-no-event>
                          <div>
                            <Typography variant="title-lg">Advanced Settings</Typography>
                            <Typography variant="body-lg" c="carbon.7">
                              Advanced settings can only be used for clusters with a monthly spending limit.
                            </Typography>
                          </div>
                        </Accordion.Control>
                        <Accordion.Panel>
                          <AdvancedSettings
                            names={{ encrypted: 'serverless.encrypted', ha: 'serverless.highAvailabilityType' }}
                            encryptedOptions={{
                              disabled: true,
                              tooltip: 'This option is inherited from the source cluster, and is not allowed to change.'
                            }}
                          />
                        </Accordion.Panel>
                      </Accordion.Item>
                    )}
                  </Accordion>
                </>
              )}
            </Card>
          </Box>

          <Box w={408} miw={408}>
            <Card withBorder shadow="none">
              <Stack p={24}>
                <div>
                  <Typography variant="title-lg">Summary</Typography>
                  <Typography variant="body-md" c="carbon.7">
                    {destinationMode === ServerlessRestoreTypeEnum.NEW
                      ? 'You are restoring to a new cluster:'
                      : 'You are restoring to the current cluster:'}
                  </Typography>
                </div>

                <Stack gap={8}>
                  <SumInfoItem label="Plan" value={cluster.servicePlan} labelProps={{ w: 100 }} />
                  <SumInfoItem
                    label="Provider"
                    value={CloudProviderLabelConst[cluster.serverless?.region.cloudProvider!]}
                    labelProps={{ w: 100 }}
                  />
                  <SumInfoItem label="Region" value={cluster.serverless?.region.displayName} labelProps={{ w: 100 }} />
                  {destinationMode === ServerlessRestoreTypeEnum.NEW && (
                    <SumInfoItem
                      label="Name"
                      value={clusterName || '-'}
                      isError={!!errors.serverless?.name}
                      labelProps={{ w: 100 }}
                    />
                  )}
                  <SumInfoItem
                    label="Spending Limit"
                    value={`${moneyFormatter(monthlySpendingLimit ?? 0)}/month`}
                    labelProps={{ w: 100 }}
                  />

                  <SumInfoItem
                    label="Restore mode"
                    value={modeOptions.find((i) => i.value === mode)?.label}
                    labelProps={{ w: 100 }}
                  />

                  <SumInfoItem
                    label="Restore from"
                    value={
                      mode === 'pitr'
                        ? pitrDate
                          ? formatTime(pitrDate, {
                              showSeconds: true,
                              showTimezone: true
                            })
                          : 'Unselected'
                        : (snapshotOptions.find((i) => i.value === snapshotId)?.label ?? 'Unselected')
                    }
                    labelProps={{ w: 100 }}
                  />
                </Stack>
              </Stack>

              <Divider />

              {destinationMode !== ServerlessRestoreTypeEnum.INPLACE && (
                <Box px={24}>
                  <SpendLimitCost value={monthlySpendingLimit ?? 0} />
                </Box>
              )}

              <Divider />

              <Group justify="flex-end" p={24}>
                <Button variant="default" onClick={onCancel} data-mp-event="Serverless Restore Cancel Clicked">
                  Cancel
                </Button>
                {creditAddVisible ? (
                  <AccessGuard
                    id="BillingPaymentCreation"
                    fallback={
                      <Tooltip
                        withinPortal
                        multiline
                        sx={{ flexGrow: 1, maxWidth: 320 }}
                        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="Serverless Restore Add Credit Card Clicked">
                            Add Credit Card
                          </Button>
                        </Box>
                      </Tooltip>
                    }
                  >
                    <Button
                      disabled={isLoadingBackupListData || isFetchingRetention}
                      onClick={creditModalHandlers.open}
                      sx={{ flexGrow: 1 }}
                      data-mp-event="Serverless Restore Add Credit Card Button Clicked"
                    >
                      Add Credit Card
                    </Button>
                  </AccessGuard>
                ) : (
                  <Button
                    type="submit"
                    disabled={disableSubmit}
                    loading={
                      restore.isLoading || isLoadingBackupListData || isLoadingSpendLimitDetails || isFetchingRetention
                    }
                    data-mp-event="Serverless Restore Submit Clicked"
                    sx={{ flex: 1 }}
                  >
                    Restore
                  </Button>
                )}

                {creditAddVisible && (
                  <PaymentMethodModal
                    open={creditModalVisible}
                    onClose={creditModalHandlers.close}
                    onComplete={() => {
                      creditModalHandlers.close()
                      notifier.success('Your credit card was added successfully!')
                    }}
                  />
                )}
              </Group>

              <Box px={24} pb={16}>
                <FormErrorMessage message={getErrorMessage(restore.error, true)} />
              </Box>
            </Card>
          </Box>
        </Box>
      </ClusterPageShell>
    </FormProvider>
  )
})
