import { Accordion, Alert, Box, List, Loader, notifier, Stack, TextInput, Typography } from '@tidbcloud/uikit'
import { FormTextInput } from '@tidbcloud/uikit/biz'
import { useDebouncedValue } from '@tidbcloud/uikit/hooks'
import { observer } from 'mobx-react'
import { useEffect, useMemo } from 'react'
import { useFormContext } from 'react-hook-form'

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

import { HeadLabel } from '../../components'
import { CreationFormValueState } from '../../helpers'
import { useCreationStore } from '../../store'

interface RegionalCIDRProps {
  provider: string
  region: string
}

export const RegionalCIDR = observer(({ provider, region }: RegionalCIDRProps) => {
  const {
    store: {
      lastVisitLocation: { orgId, projectId }
    }
  } = useStores()
  const { dedicated: { setCidrConfigured } = {} } = useCreationStore()
  const { watch, setValue, setError, clearErrors, formState } = useFormContext<CreationFormValueState>()

  const { errors } = formState

  const upperProvider = provider.toUpperCase() as ListCidrsProvider
  const latestCIDRQuery = useListCidrs(
    orgId,
    projectId,
    {
      provider: upperProvider
    },
    {
      query: {
        enabled: !!(orgId && projectId && provider && region),
        refetchOnWindowFocus: false,
        onError: (err) => {
          const errMsg = getErrorMessage(err, true)

          notifier.error(<div dangerouslySetInnerHTML={{ __html: errMsg }} />)
        }
      }
    }
  )
  const latestCIDRVal = useMemo(
    () => latestCIDRQuery.data?.items?.find((item) => item.region?.name === region)?.cidr,
    [latestCIDRQuery.data?.items, region]
  )
  const configured = !!latestCIDRVal

  /**
   * Call `setCidrConfigured` in effect instead of
   * in `onSuccess` callback of `useListCidrs`.
   * Because `onSuccess` only fires on request finished,
   * not on the result of `select` callback updated.
   */
  useEffect(() => {
    if (latestCIDRQuery.isSuccess) {
      setCidrConfigured?.(!!latestCIDRVal)
    }
  }, [latestCIDRQuery.isSuccess, latestCIDRVal, setCidrConfigured])

  useEffect(() => {
    if (configured) {
      clearErrors('dedicated.projectCIDR')
    }
  }, [clearErrors, configured])

  const defaultCidrQuery = useGetDefaultCidr(
    orgId,
    projectId,
    {
      provider: upperProvider,
      region
    },
    {
      query: {
        enabled: !configured && !!(orgId && projectId && provider && region),
        refetchOnWindowFocus: false,
        onSuccess: (data) => {
          const isDirty = !!formState.dirtyFields?.dedicated?.projectCIDR

          if (!isDirty || !!errors?.dedicated?.projectCIDR) {
            setValue('dedicated.projectCIDR', data?.cidr)
            clearErrors('dedicated.projectCIDR')
          }
        },
        onError: (err) => {
          const errMsg = getErrorMessage(err, true)

          notifier.error(<div dangerouslySetInnerHTML={{ __html: errMsg }} />)
        }
      }
    }
  )

  const { projectCIDR: cidrVal } = watch('dedicated')
  const [debouncedCIDR] = useDebouncedValue(cidrVal, 300)
  const {
    query: { data: { max_node_ip: maxIPNum, overlaps } = {} }
  } = useGetCIDRValidation(
    {
      provider: upperProvider,
      region,
      cidr: debouncedCIDR,
      disabled: configured || !cidrRegEx.test(debouncedCIDR)
    },
    {
      query: {
        refetchOnWindowFocus: false,
        retry: false,
        onSuccess: () => {
          clearErrors('dedicated.projectCIDR')
        },
        onError: (err) => {
          const { message = 'Please enter a valid CIDR.' } = pickErrorResponse(err)

          if (!configured) {
            setError('dedicated.projectCIDR', {
              message
            })
          }
        }
      }
    }
  )
  const overlapped = !!overlaps?.length

  const loading = latestCIDRQuery.isLoading || defaultCidrQuery.isLoading

  return (
    <>
      <Accordion.Control data-mp-no-event>
        <HeadLabel
          label="Project CIDR"
          description="A CIDR to be used as the network address for peering with your application VPC."
        />
      </Accordion.Control>
      <Accordion.Panel>
        {configured && (
          <Stack gap="md">
            <TextInput disabled value={latestCIDRVal} />
            <Alert>
              CIDR has been created for this region and it can not be updated after the first cluster is created in this
              region. To use a different CIDR, you have the option to create the cluster within alternative projects.
            </Alert>
          </Stack>
        )}
        {!configured && (
          <Stack gap="md">
            <Box>
              <FormTextInput name="dedicated.projectCIDR" rightSection={loading ? <Loader size="xs" /> : void 0} />
              {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 project CIDR can not be modified after the cluster is created. Please ensure it does not overlap with
              your application VPC CIDR.{' '}
              <a
                href="https://docs.pingcap.com/tidbcloud/set-up-vpc-peering-connections"
                target="_blank"
                rel="noreferrer"
              >
                Learn more
              </a>
            </Alert>
          </Stack>
        )}
      </Accordion.Panel>
    </>
  )
})
