import {
  Alert,
  Box,
  Button,
  Checkbox,
  Divider,
  Group,
  HoverCard,
  LoadingOverlay,
  Modal,
  SegmentedControl,
  SimpleGrid,
  Stack,
  TextInput,
  Typography,
  notifier
} from '@tidbcloud/uikit'
import { FormErrorMessage, FormNumberInput, FormSelect, FormSwitch } from '@tidbcloud/uikit/biz'
import { capitalize, isEqual } from 'lodash-es'
import { type ChangeEvent, useEffect, useMemo, useRef, useState } from 'react'
import { Controller, FormProvider, useForm } from 'react-hook-form'

import { CloudProviderConst } from 'dbaas/features/Project'
import { useGetBackupOptions, useModifyBackupSettingV2, useQueryBackupSettingV2 } from 'dbaas/services/dataflow'
import {
  DataflowBackupSettingActionType,
  DataflowSnapshotBackupScheduleType,
  DataflowWeekDay
} from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { formatTime, getUTCString } from 'dbaas/utils/format'

import {
  FieldDisableWarnings,
  defaultValues,
  fromFormValues,
  getSettingStatusWarning,
  matchFormChangeState,
  toFormValues
} from './backupSettingUtils'
import { times, toUTCBackupTime, toUTCWeekdays } from './utils'

export type SettingFormValuesV3 = typeof defaultValues

// --- Main Component ---
export const BackupSettingV3 = ({ closeModal }: { closeModal: () => void }) => {
  const {
    store: {
      tenantData,
      activeProjectId,
      currentCluster,
      activeProject: { aws_cmek_enabled: isAwsCmekEnabled }
    }
  } = useStores()

  const methods = useForm<SettingFormValuesV3>({
    defaultValues
  })
  const {
    control,
    handleSubmit,
    setValue,
    watch,
    reset,
    resetField,
    formState: { isDirty, dirtyFields, errors }
  } = methods

  // Fetch initial backup settings
  const {
    data: backupSetting,
    isFetching: isLoadingSetting,
    error: errorLoadingSetting,
    isError: isErrorLoadingSetting
  } = useQueryBackupSettingV2(tenantData.id, activeProjectId, currentCluster?.id!, {
    query: {
      enabled: !!tenantData.id && !!activeProjectId && !!currentCluster?.id,
      refetchOnWindowFocus: false,
      onSuccess(data) {
        const formValues = toFormValues(data, tenantData.timezone)
        reset(formValues) // Reset form with fetched values
      }
    }
  })

  // Fetch dual region options
  const {
    data: backupOptions,
    isFetching: isLoadingOptions,
    error: errorLoadingOptions,
    isError: isErrorLoadingOptions
  } = useGetBackupOptions(tenantData.id, activeProjectId, currentCluster?.id!, {
    query: {
      enabled: !!tenantData.id && !!activeProjectId && !!currentCluster?.id,
      refetchOnWindowFocus: false
    }
  })

  // Memoize initial values from the first successful fetch
  const initialValues = useMemo(() => {
    if (backupSetting) {
      return toFormValues(backupSetting, tenantData.timezone)
    }
    return defaultValues // Use defaults until fetch succeeds
  }, [backupSetting, tenantData.timezone])

  // Watch relevant form fields
  const autoBackupEnable = watch('auto_backup_enable')
  const dualRegionEnable = watch('dual_region')
  const scheduleType = watch('schedule_type')
  const pitrValue = watch('pitr')

  // Mutation hook
  const modifySetting = useModifyBackupSettingV2()

  // Calculate derived states and warnings
  const isWeekly = scheduleType === DataflowSnapshotBackupScheduleType.Weekly

  const statusWarning = useMemo(
    () =>
      getSettingStatusWarning(
        backupSetting?.status!,
        backupSetting?.actions!,
        pitrValue // Use current form value
      ),
    [backupSetting?.status, backupSetting?.actions, pitrValue]
  )

  const selectedDualRegion = watch('selected_dual_region')
  const transitionalWarning = useMemo(() => {
    if (!initialValues || !isDirty) return null // Only show when dirty and initial values loaded

    return matchFormChangeState(
      { pitr: !!initialValues.pitr, dualRegion: !!initialValues.dual_region },
      { pitr: pitrValue, dualRegion: dualRegionEnable },
      {
        dualRegionName: backupOptions?.dual_region_options.region_options
          ?.map((i) => i.region)
          .find((i) => i?.name === selectedDualRegion)?.display_name
      }
    )
  }, [initialValues, isDirty, pitrValue, dualRegionEnable, backupOptions, selectedDualRegion])

  // Determine edit permissions from API response
  const canEditPitr = backupSetting?.actions?.includes(DataflowBackupSettingActionType.Edit_PiTR) ?? false // Default to false until loaded
  const canEditRegion = backupSetting?.actions?.includes(DataflowBackupSettingActionType.Edit_Region) ?? false
  const canEditSchedule = backupSetting?.actions?.includes(DataflowBackupSettingActionType.Edit_Schedule) ?? false

  // Determine if a conflicting setting has been changed in this session
  const pitrDirty = dirtyFields.pitr
  const pitrDailyLastValueByUserRef = useRef(initialValues?.pitr ?? false)
  const pitrWeeklyLastValueByUserRef = useRef(initialValues?.pitr ?? true)
  const dualRegionDirty = dirtyFields.dual_region || dirtyFields.selected_dual_region
  const [pitrDisableConfirmOpened, setPitrDisableConfirmOpened] = useState(false)

  const rememberPitrValueBySchedule = (checked: boolean) => {
    if (isWeekly) {
      pitrWeeklyLastValueByUserRef.current = checked
    } else {
      pitrDailyLastValueByUserRef.current = checked
    }
  }

  const handlePitrChange = (e: ChangeEvent<HTMLInputElement>) => {
    const checked = e.currentTarget.checked

    if (initialValues.pitr && pitrValue && !checked) {
      resetField('pitr', { defaultValue: initialValues.pitr })
      setPitrDisableConfirmOpened(true)
      return
    }

    rememberPitrValueBySchedule(checked)
  }

  const handleConfirmPitrDisable = () => {
    setValue('pitr', false, { shouldDirty: true })
    rememberPitrValueBySchedule(false)
    setPitrDisableConfirmOpened(false)
  }

  // PITR switch disabled state and tooltip
  const pitrIsEffectivelyDisabled =
    !autoBackupEnable || // Disabled if auto backup is off
    !canEditPitr || // Disabled by API status/actions
    (isDirty && dualRegionDirty) // Disabled if dual region was also changed

  const pitrDisableTip = useMemo(() => {
    if (!autoBackupEnable) return 'Enable Auto Backup to configure Point-in-time Restore.'
    if (!canEditPitr && statusWarning) return statusWarning // Show status warning if applicable
    if (isDirty && dualRegionDirty) return FieldDisableWarnings.DualRegionOrPointInTimeExclusiveChange
    return undefined
  }, [autoBackupEnable, isWeekly, canEditPitr, statusWarning, isDirty, dualRegionDirty])

  // Dual Region switch disabled state and tooltip
  const dualRegionIsEffectivelyDisabled =
    isAwsCmekEnabled ||
    !autoBackupEnable || // Disabled if auto backup is off
    !canEditRegion || // Disabled by API status/actions
    (isDirty && pitrDirty) // Disabled if PITR was also changed

  const dualRegionDisableTip = useMemo(() => {
    if (isAwsCmekEnabled) return 'Dual Region Backup is not supported if CMEK is enabled.'
    if (!autoBackupEnable) return 'Enable Auto Backup to configure Dual Region Backup.'
    if (!canEditRegion && statusWarning) return statusWarning // Show status warning if applicable
    if (isDirty && pitrDirty) return FieldDisableWarnings.DualRegionOrPointInTimeExclusiveChange
    return undefined
  }, [autoBackupEnable, canEditRegion, statusWarning, isDirty, pitrDirty, isAwsCmekEnabled])

  useEffect(() => {
    pitrWeeklyLastValueByUserRef.current =
      initialValues.schedule_type === DataflowSnapshotBackupScheduleType.Weekly ? (initialValues?.pitr ?? false) : true
    pitrDailyLastValueByUserRef.current =
      initialValues.schedule_type === DataflowSnapshotBackupScheduleType.Daily ? (initialValues?.pitr ?? false) : false
  }, [initialValues.pitr, initialValues.schedule_type])

  // Specific check for disabling the *select* dropdown for dual region
  // Cannot change region directly if it was already enabled initially. Must disable first.
  const dualRegionSelectIsDisabled = initialValues?.dual_region === true
  const dualRegionSelectDisableTip =
    'Directly switching to another region is not supported. To change the region, first disable Dual Region Backup, save, then re-enable it and select the new desired region.'

  // Form submission handler
  const onSubmit = async (formData: SettingFormValuesV3) => {
    // Use initialValues from the memoized state based on the first successful fetch
    const actualInitialValues = initialValues

    if (!isDirty || isEqual(formData, actualInitialValues)) {
      closeModal()
      return
    }

    const clusterRegion = backupSetting?.regions?.find((i) => i.name === currentCluster?.region)
    const selectedBackupRegion = backupOptions?.dual_region_options.region_options
      ?.map((i) => i.region)
      .find((i) => i?.name === formData.selected_dual_region)

    if (!clusterRegion) {
      notifier.error('Could not determine the primary cluster region.')
      return
    }
    if (formData.auto_backup_enable && formData.dual_region && !selectedBackupRegion) {
      // Only require selected region if auto backup and dual region are enabled
      notifier.error('Please select a secondary region for backup.')
      return
    }

    // Adjust time/weekdays to UTC before creating payload
    const utcBackupTime = toUTCBackupTime(formData.backup_time, tenantData.timezone)
    const utcWeekdays = toUTCWeekdays(formData.weekdays, formData.backup_time, tenantData.timezone)

    const body = fromFormValues(
      {
        ...formData,
        backup_time: utcBackupTime,
        weekdays: utcWeekdays
      },
      clusterRegion,
      selectedBackupRegion
    )

    try {
      await modifySetting.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: currentCluster?.id!,
        data: { ...body, dry_run: false }
      })
      notifier.success('Backup settings saved successfully.')
      closeModal()
    } catch (e: any) {
      notifier.error(`Failed to save backup settings: ${getErrorMessage(e)}`)
      console.error('Error saving backup settings:', e)
    }
  }

  // Loading/Error states
  const isLoading = isLoadingSetting || isLoadingOptions
  const isError = isErrorLoadingSetting || isErrorLoadingOptions
  const error = errorLoadingSetting || errorLoadingOptions

  // Moved hooks before potential early return
  const currentRegionDisplayName = backupOptions?.dual_region_options.cluster_region?.display_name
  const availableDualRegions = backupOptions?.dual_region_options.region_options?.map((i) => ({
    label: i.region?.display_name!,
    value: i.region?.name!
  }))

  if (isError && !backupSetting) {
    // Only show full error if initial load failed
    return <FormErrorMessage p="md" message={getErrorMessage(error)} />
  }

  return (
    <FormProvider {...methods}>
      <form onSubmit={handleSubmit(onSubmit)}>
        <LoadingOverlay visible={isLoading} overlayProps={{ blur: 1 }} />
        <Stack>
          {/* Auto Backup Section */}
          <Stack gap="xs">
            <Group justify="space-between" align="center" wrap="nowrap">
              <Stack gap={4} style={{ flexGrow: 1 }}>
                <Typography variant="title-lg">Auto Backup</Typography>
                <Typography variant="body-lg" c="gray.7">
                  Enable auto backup to configure a backup schedule for your cluster to periodically back up your data.
                </Typography>
              </Stack>
              {/* Disable switch if schedule editing is disallowed by status */}
              <FormSwitch name="auto_backup_enable" disabled={!canEditSchedule} data-testid="auto-backup" />
            </Group>

            {/* Conditional Auto Backup Settings */}
            {autoBackupEnable && (
              <Box
                mt="md"
                bg="carbon.2"
                p={24}
                style={{
                  borderRadius: 'var(--mantine-radius-md)'
                }}
              >
                <Stack gap="md">
                  {/* Backup Cycle */}
                  <Stack gap={4}>
                    <Typography variant="label-md" fz={14}>
                      Backup Cycle
                    </Typography>
                    <Controller
                      control={control}
                      name="schedule_type"
                      disabled={!canEditSchedule}
                      render={({ field }) => (
                        <SegmentedControl
                          {...field}
                          onChange={(value) => {
                            field.onChange(value)

                            if (value === DataflowSnapshotBackupScheduleType.Weekly) {
                              setValue('pitr', pitrWeeklyLastValueByUserRef.current, {
                                shouldDirty: initialValues?.pitr === pitrWeeklyLastValueByUserRef.current
                              })
                            } else if (
                              value === DataflowSnapshotBackupScheduleType.Daily &&
                              pitrDailyLastValueByUserRef.current === false
                            ) {
                              // if not dirty, when switch to daily, set to initial value
                              setValue('pitr', false, { shouldDirty: false })
                            }
                          }}
                          data={[
                            { label: 'Daily Backup', value: DataflowSnapshotBackupScheduleType.Daily },
                            { label: 'Weekly Backup', value: DataflowSnapshotBackupScheduleType.Weekly }
                          ]}
                        />
                      )}
                    />
                  </Stack>

                  {/* Weekly Backup Day Selection */}
                  {isWeekly && (
                    <Controller
                      name="weekdays"
                      control={control}
                      rules={{
                        validate: (val) => {
                          if (!canEditSchedule) return undefined // Don't validate if disabled
                          if (!val || val.length === 0) return 'Select at least one day'
                          return undefined
                        }
                      }}
                      render={({ field }) => (
                        <Checkbox.Group
                          onChange={(values) => {
                            field.onChange(values)
                          }}
                          value={field.value}
                          error={errors.weekdays?.message}
                        >
                          <SimpleGrid
                            cols={4}
                            p={24}
                            bg="carbon.0"
                            style={{
                              border: '1px solid var(--mantine-color-carbon-4)',
                              borderRadius: 'var(--mantine-radius-md)'
                            }}
                          >
                            {Object.values(DataflowWeekDay).map((i) => (
                              <Checkbox label={capitalize(i)} key={i as string} value={i} disabled={!canEditSchedule} />
                            ))}
                          </SimpleGrid>
                        </Checkbox.Group>
                      )}
                    />
                  )}

                  <Group wrap="nowrap" grow justify="space-between">
                    {/* Backup Time */}
                    <FormSelect
                      label="Backup Time"
                      name="backup_time"
                      data={times}
                      rightSection={
                        <Typography variant="body-lg" c="gray.8">
                          {getUTCString(tenantData.timezone)}
                        </Typography>
                      }
                      disabled={!canEditSchedule}
                      styles={{
                        root: {
                          '& [data-position="right"]': {
                            width: 'fit-content',
                            backgroundColor: 'var(--mantine-color-carbon-2)',
                            paddingLeft: 12,
                            paddingRight: 12,
                            borderLeft: '1px solid var(--mantine-color-carbon-4)'
                          }
                        }
                      }}
                    />

                    {/* Backup Retention */}
                    <FormNumberInput
                      label="Backup Retention"
                      name="retention_period"
                      step={1}
                      min={1}
                      max={90} // Keep max from V2
                      rules={{ required: 'Required' }}
                      rightAddon={<Typography c="gray.8">Days</Typography>}
                      disabled={!canEditSchedule}
                    />
                  </Group>

                  {/* Point-in-time Restore */}
                  <Stack gap="xs">
                    <Group justify="space-between" wrap="nowrap">
                      <Stack gap={4} style={{ flexGrow: 1, marginRight: 'var(--mantine-spacing-md)' }}>
                        <Typography variant="label-lg">Point-in-time Restore</Typography>
                        <Typography variant="body-lg" c="gray.7">
                          Point-in-time restore provides the capability to restore to any desired point in time within
                          the designated backup retention period. This functionality aligns seamlessly with a Recovery
                          Point Objective of 5 minutes.
                        </Typography>
                      </Stack>
                      <HoverCard disabled={!pitrIsEffectivelyDisabled || !pitrDisableTip} withArrow shadow="md">
                        <HoverCard.Target>
                          <Box>
                            <FormSwitch name="pitr" disabled={pitrIsEffectivelyDisabled} onChange={handlePitrChange} />
                          </Box>
                        </HoverCard.Target>
                        <HoverCard.Dropdown maw={300}>{pitrDisableTip}</HoverCard.Dropdown>
                      </HoverCard>
                    </Group>
                    {isWeekly && (
                      <Alert color="yellow" mt="xs">
                        We always Recommend Not To Disable Point-in-time Restore(PiTR)! Because Disabling PiTR removes
                        point-in-time recovery within the backup retention period. Recovery will be limited to weekly
                        full backup snapshots, increasing your RPO to up to 7 days. Please carefully consider the impact
                        before proceeding.
                      </Alert>
                    )}
                  </Stack>
                </Stack>
              </Box>
            )}
          </Stack>

          <Divider mx={-24} my={8} />

          {/* Dual Region Backup Section - Render based on provider */}
          {currentCluster?.provider !== CloudProviderConst.AZURE && (
            <>
              <Stack gap="xs">
                <Group justify="space-between" wrap="nowrap">
                  <Stack gap={4} style={{ flexGrow: 1, marginRight: 'var(--mantine-spacing-md)' }}>
                    <Typography variant="title-lg">Dual Region Backup</Typography>
                    <Typography variant="body-lg" c="gray.7">
                      Enable cross-region disaster recovery and improve availability by copying backups to an additional
                      region. By default, backups are stored in the same region as the cluster. Turning on this feature
                      adds a region for backup replication.
                    </Typography>
                  </Stack>

                  <HoverCard disabled={!dualRegionIsEffectivelyDisabled || !dualRegionDisableTip} withArrow shadow="md">
                    <HoverCard.Target>
                      <Box pt={4}>
                        <FormSwitch name="dual_region" disabled={dualRegionIsEffectivelyDisabled} />
                      </Box>
                    </HoverCard.Target>
                    <HoverCard.Dropdown maw={300}>{dualRegionDisableTip}</HoverCard.Dropdown>
                  </HoverCard>
                </Group>

                {/* Conditional Dual Region Settings */}
                {dualRegionEnable && (
                  // Indentation styling
                  <Box
                    mt="md"
                    bg="carbon.2"
                    p={24}
                    style={{
                      borderRadius: 'var(--mantine-radius-md)'
                    }}
                  >
                    <Stack gap="md">
                      <Group wrap="nowrap" grow gap="xl">
                        {/* Primary Region Display */}
                        <TextInput
                          label="Primary Region"
                          value={currentRegionDisplayName}
                          readOnly
                          disabled // Visually indicate it's not interactive
                          // Style as disabled input
                          styles={{ input: { backgroundColor: 'var(--mantine-color-gray-1)', cursor: 'not-allowed' } }}
                        />

                        {/* Secondary Region Select */}
                        <HoverCard disabled={!dualRegionSelectIsDisabled} withArrow shadow="md">
                          <HoverCard.Target>
                            <Box>
                              <FormSelect
                                label="Secondary Region"
                                name="selected_dual_region"
                                placeholder="Select another region for backup"
                                data={availableDualRegions}
                                disabled={dualRegionIsEffectivelyDisabled || dualRegionSelectIsDisabled}
                                rules={{ required: 'Required' }} // Required only if dual region enabled
                                withAsterisk
                                searchable // Make it searchable if many regions
                                nothingFoundMessage="No regions available"
                              />
                            </Box>
                          </HoverCard.Target>
                          <HoverCard.Dropdown maw={300}>{dualRegionSelectDisableTip}</HoverCard.Dropdown>
                        </HoverCard>
                      </Group>
                    </Stack>
                  </Box>
                )}
              </Stack>
              <Divider mx={-24} my={8} />
            </>
          )}

          {!autoBackupEnable && (
            <Alert color="yellow">
              We strongly recommend keeping Auto Backup enabled. Auto Backup allows you to restore data to a previous
              state in case of emergencies.
            </Alert>
          )}

          {statusWarning && <Alert color="yellow">{statusWarning}</Alert>}

          {transitionalWarning && <Alert color="yellow">{transitionalWarning}</Alert>}

          {/* Next Backup Time */}
          {autoBackupEnable && backupSetting?.snapshot_backup_schedule?.next_backup_time && (
            <Alert color="peacock">
              {`The next backup task will start at ${formatTime(
                backupSetting?.snapshot_backup_schedule?.next_backup_time,
                { showTimezone: true, offset: tenantData.timezone }
              )}.`}
            </Alert>
          )}

          {/* Display mutation error if any */}
          {modifySetting.error && <Alert color="red">{getErrorMessage(modifySetting.error)}</Alert>}

          {/* Bottom Section */}
          <Group justify="space-between" align="center" mt={16}>
            {/* Use correct link from V2 */}
            <Typography variant="body-sm">
              <a
                href="https://www.pingcap.com/tidb-dedicated-pricing-details/#backup-storage-cost"
                target="_blank"
                rel="noreferrer"
              >
                View Pricing docs for more detail
              </a>
            </Typography>
            <Group>
              <Button variant="default" onClick={closeModal} type="button">
                Cancel
              </Button>
              <Button
                type="submit"
                loading={modifySetting.isLoading}
                // Disable save if no changes, loading initial data, or mutation ongoing, or form edits are blocked by status
                disabled={isLoading || modifySetting.isLoading || !isDirty}
              >
                Save
              </Button>
            </Group>
          </Group>
        </Stack>
      </form>
      <Modal
        opened={pitrDisableConfirmOpened}
        onClose={() => setPitrDisableConfirmOpened(false)}
        title="Disable Point-in-Time Restore?"
        centered
        size="md"
        data-testid="disable-pitr-confirm-modal"
      >
        <Stack>
          <Typography variant="body-lg">
            Disabling PITR means you will not be able to restore to any point in time from this moment forward. If you
            re-enable PITR later, the intermediate time period will not be recoverable.
          </Typography>
          <Typography variant="body-lg">
            Re-enabling PITR requires taking a new full snapshot before point-in-time recovery can resume.
          </Typography>
          <Group justify="flex-end" mt="md">
            <Button variant="default" type="button" onClick={() => setPitrDisableConfirmOpened(false)}>
              Cancel
            </Button>
            <Button type="button" onClick={handleConfirmPitrDisable}>
              Confirm
            </Button>
          </Group>
        </Stack>
      </Modal>
    </FormProvider>
  )
}
