import { Alert, Box, List, Loader, Modal, Typography } from '@tidbcloud/uikit'
import { Form, FormSelect, FormTextInput } from '@tidbcloud/uikit/biz'
import { useDebouncedValue } from '@tidbcloud/uikit/hooks'
import { observer } from 'mobx-react'
import { useEffect, useMemo } from 'react'
import { useForm } from 'react-hook-form'

import { useFetchProviders } from 'dbaas/features/ClusterManagement/common'
import { CloudProvider, CloudProviderConst, getCloudProviderLabel, useGetCIDRValidation } from 'dbaas/features/Project'
import { useCreateCidr, useGetDefaultCidr, useListCidrs } from 'dbaas/services/api-clients/legacy/central'
import { ListCidrsProvider } from 'dbaas/services/api-clients/legacy/central/interface'
import { pickErrorResponse } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { cidrRegEx } from 'dbaas/utils/regex'

interface CreationModalContentProps {
  provider: CloudProvider
  onClose: () => void
  onConfirm?: () => void
}

export const CreationModalContent = observer(({ provider, onClose, onConfirm }: CreationModalContentProps) => {
  const {
    store: {
      lastVisitLocation: { orgId, projectId }
    }
  } = useStores()

  const form = useForm<{ region: string; cidr: string }>({
    mode: 'onChange',
    reValidateMode: 'onChange',
    defaultValues: {
      region: '',
      cidr: ''
    }
  })
  const { watch, setValue, setError, clearErrors, formState } = form
  const { region, cidr } = watch()

  const providerUppercase = provider.toUpperCase() as ListCidrsProvider
  const {
    query: { isLoading: providerLoading, data: allRegions = [] }
  } = useFetchProviders(
    { tier: 'dedicated' },
    {
      query: {
        refetchOnWindowFocus: false,
        select: (data) => data?.cloud_providers?.find((p) => p.name.toLowerCase() === provider)?.regions
      }
    }
  )
  const {
    data: excludedRegionNames,
    isLoading: cidrListLoading,
    refetch: refetchCIDRList
  } = useListCidrs(
    orgId,
    projectId,
    { provider: providerUppercase },
    {
      query: {
        refetchOnMount: false,
        refetchOnWindowFocus: false,
        select: (data) => data?.items?.map((c) => c.region?.name)
      }
    }
  )
  const regionOptions = useMemo(
    () =>
      allRegions.map((r) => ({
        value: r.name,
        label: r.display_name,
        disabled: excludedRegionNames?.includes(r.name)
      })),
    [allRegions, excludedRegionNames]
  )

  const regionDisabled = regionOptions.every((r) => r.disabled)
  const regionLoading = providerLoading || cidrListLoading

  useEffect(() => {
    const enabledRegions = regionOptions.filter((r) => !r.disabled).map((r) => r.value)

    if (!region || !enabledRegions.includes(region)) {
      setValue('region', enabledRegions[0] || '')
    }
  }, [region, regionOptions, setValue])

  const { isFetching: defaultCIDRLoading } = useGetDefaultCidr(
    orgId,
    projectId,
    {
      provider: providerUppercase,
      region
    },
    {
      query: {
        enabled: !!(orgId && projectId && provider && region),
        refetchOnWindowFocus: false,
        onSuccess: (data) => {
          const isDirty = !!formState.dirtyFields?.cidr

          if (!isDirty || !!formState.errors?.cidr) {
            setValue('cidr', data?.cidr)
            clearErrors('cidr')
          }
        }
      }
    }
  )
  const [debouncedCIDR] = useDebouncedValue(cidr, 500)
  const {
    query: { data: { max_node_ip: maxIPNum, overlaps } = {}, isLoading: validating }
  } = useGetCIDRValidation(
    {
      provider: providerUppercase,
      region,
      cidr: debouncedCIDR,
      disabled: !cidrRegEx.test(debouncedCIDR)
    },
    {
      query: {
        refetchOnWindowFocus: false,
        retry: false,
        onSuccess: () => {
          clearErrors('cidr')
        },
        onError: (err) => {
          const { message = 'Please input a valid CIDR.' } = pickErrorResponse(err)

          setError('cidr', {
            message
          })
        }
      }
    }
  )
  const overlapped = !!overlaps?.length

  const createCIDR = useCreateCidr({
    mutation: {
      onSuccess: async () => {
        await refetchCIDRList()
        onConfirm?.()
        onClose?.()
      }
    }
  })
  const onSubmit = async () => {
    createCIDR.mutateAsync({
      orgId,
      projectId,
      data: {
        region: {
          provider: providerUppercase,
          name: region
        },
        cidr: debouncedCIDR
      }
    })
  }

  const providerLabel = getCloudProviderLabel(provider)

  return (
    <Form
      form={form}
      onSubmit={onSubmit}
      onCancel={onClose}
      actionsProps={{
        cancelProps: {
          'data-mp-event': `${providerLabel} CIDR creation cancel button clicked`
        },
        confirmProps: {
          disabled: regionDisabled || validating || !!formState.errors?.cidr,
          loading: createCIDR.isLoading,
          'data-mp-event': `${providerLabel} CIDR creation confirm button clicked`
        }
      }}
    >
      <Typography variant="body-lg">
        CIDR will be used as the network address for peering with your application VPC. Learn more about{' '}
        <a href="https://docs.pingcap.com/tidbcloud/set-up-vpc-peering-connections" target="_blank" rel="noreferrer">
          connect to TiDB Dedicated via VPC Peering
        </a>
        .
      </Typography>
      <FormSelect
        name="region"
        label={`${providerLabel} Region`}
        data={regionOptions}
        disabled={regionDisabled}
        placeholder={regionDisabled ? 'CIDR has been configured on all regions' : 'Please select a region'}
        rightSection={regionLoading ? <Loader size="xs" /> : void 0}
      />
      <Box>
        <FormTextInput
          name="cidr"
          label="CIDR"
          disabled={regionDisabled}
          placeholder={regionDisabled ? '-' : void 0}
          rightSection={defaultCIDRLoading ? <Loader size="xs" /> : void 0}
          rules={{
            required: 'Please enter your CIDR',
            pattern: {
              value: cidrRegEx,
              message: 'Please enter a valid CIDR.'
            }
          }}
        />
        {maxIPNum && (
          <Typography variant="body-sm" color="carbon.7" mt={8}>
            This CIDR setting can support up to {maxIPNum} nodes in the region.
          </Typography>
        )}
      </Box>
      {overlapped && (
        <Alert color="yellow">
          <Typography variant="body-lg" color="inherit">
            The CIDR overlaps with the existing CIDR settings.
            <List c="inherit" fz="inherit" my={8}>
              {overlaps
                .flatMap((o) => o.regions?.map((region) => ({ ...region, project_id: o.project_id })))
                .map((el, i) => (
                  <List.Item key={i}>
                    <Typography span variant="label-lg" color="inherit">
                      {el?.display_name || el?.name}
                    </Typography>{' '}
                    region in{' '}
                    {el?.project_id === projectId ? (
                      'current project'
                    ) : (
                      <>
                        project ID{' '}
                        <Typography span variant="label-lg" color="inherit">
                          {el?.project_id}
                        </Typography>
                      </>
                    )}
                  </List.Item>
                ))}
            </List>
            This overlap will block you from establishing VPC peering between these regions.
          </Typography>
        </Alert>
      )}
      <Typography variant="body-lg">
        {provider === CloudProviderConst.AWS && 'We recommend configuring an IP range size between /16 and /23.'}
        {provider === CloudProviderConst.GCP && 'We recommend configuring an IP range size between /16 and /20.'}
        {provider === CloudProviderConst.AZURE && 'We recommend configuring an IP range size between /16 and /20.'}
      </Typography>
      <Typography variant="body-lg">The following network addresses are supported:</Typography>
      <List
        size="sm"
        c="carbon.8"
        bg="carbon.2"
        fz={13}
        p={8}
        sx={(theme) => ({
          border: `1px solid ${theme.colors.carbon[4]}`,
          borderRadius: theme.defaultRadius
        })}
      >
        {provider === CloudProviderConst.AWS && (
          <>
            <List.Item>10.250.0.0 - 10.251.255.255</List.Item>
            <List.Item>172.16.0.0 - 172.31.255.255</List.Item>
            <List.Item>192.168.0.0 - 192.168.255.255</List.Item>
          </>
        )}
        {provider === CloudProviderConst.GCP && (
          <>
            <List.Item>10.250.0.0 - 10.251.255.255</List.Item>
            <List.Item>172.16.0.0 - 172.17.255.255</List.Item>
            <List.Item>172.30.0.0 - 172.31.255.255</List.Item>
          </>
        )}
        {provider === CloudProviderConst.AZURE && (
          <>
            <List.Item>10.250.0.0 - 10.251.255.255 </List.Item>
            <List.Item>172.16.0.0 - 172.20.255.255</List.Item>
          </>
        )}
      </List>
      <Alert>
        The CIDR can not be modified after the cluster is created. Please ensure it does not overlap with your
        application VPC CIDR.
      </Alert>
    </Form>
  )
})

interface CreationModalProps {
  provider: CloudProvider
  opened: boolean
  onClose: () => void
  onConfirm?: () => void
}

export const CreationModal = ({ opened, provider, onClose, onConfirm }: CreationModalProps) => {
  const providerLabel = getCloudProviderLabel(provider)

  return (
    <Modal centered size="lg" opened={opened} title={`Create ${providerLabel} CIDR`} onClose={onClose}>
      <CreationModalContent provider={provider} onClose={onClose} onConfirm={onConfirm} />
    </Modal>
  )
}
