import { Box, Divider, Group, HoverCard, Input, Loader, Modal, Stack, Typography } from '@tidbcloud/uikit'
import { FormPasswordInput, FormSelect, FormTextInput } from '@tidbcloud/uikit/biz'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconInfoCircle } from '@tidbcloud/uikit/icons'
import { useEffect, useMemo } from 'react'
import { useFormContext } from 'react-hook-form'

import { useIsEditingChangefeed } from 'dbaas/features/Changefeed'
import { getChangefeedConnectionMethods } from 'dbaas/features/Changefeed/connection'
import HeadLabel from 'dbaas/screens/ClustersV2/new/components/HeadLabel'
import { CreatePrivateEndpointForChangefeed } from 'dbaas/screens/NextGen/premium/networking/private-endpoint-changefeed/Create'
import type { SharedTiDB } from 'dbaas/screens/NextGen/shared/model/shared-tidb-state'
import { useNgListSinkEndpoints } from 'dbaas/services/dataflow'
import { DataflowNetworkType } from 'dbaas/services/dataflow/interface'

import { isPrivateConnect } from '../helper'

import { buildMySQLPrivateEndpointOptions } from './mysqlPrivateEndpointOptions'

const getConnectionMethods = (cluster: SharedTiDB) => {
  const connectionMethods = getChangefeedConnectionMethods(cluster.cloudProvider!)

  if (cluster.computed.isEssentialV2) {
    return connectionMethods.filter((method) => method.value !== DataflowNetworkType.NetworkType_VPC_Peering)
  }

  return connectionMethods
}

export function FormMySQL({ cluster }: { cluster: SharedTiDB }) {
  const { watch, setValue, clearErrors } = useFormContext()
  const isEditing = useIsEditingChangefeed()
  const connectionMethods = getConnectionMethods(cluster)
  const networkType = watch('network_info.network_type')
  const isPrivateLink = isPrivateConnect(networkType)
  const [privateEndpointOpened, privateEndpointHandler] = useDisclosure()
  const canUseSinkEndpoints = cluster?.computed.isPremium || cluster?.computed.isBYOC || cluster?.computed.isEssentialV2

  const { data, isLoading, refetch } = useNgListSinkEndpoints(
    cluster.tidbId!,
    {
      status: 'SINK_ENDPOINT_STATUS_AVAILABLE'
    },
    {
      query: {
        enabled: canUseSinkEndpoints && !!cluster.tidbId && isPrivateLink,
        refetchOnMount: false,
        refetchOnWindowFocus: false
      }
    }
  )
  const privateEndpointOptions = useMemo(() => {
    return buildMySQLPrivateEndpointOptions(data?.sink_endpoints)
  }, [data])

  useEffect(() => {
    clearErrors('network_info.sink_endpoint_id')
  }, [clearErrors])

  return (
    <>
      <Divider />

      <Stack m={24} maw={1000}>
        <HeadLabel label="Connection" />

        <FormSelect
          name="network_info.network_type"
          label={
            <Input.Label mb={0}>
              <Group gap={8}>
                <span>Connectivity Method</span>
                <HoverCard shadow="md" withArrow withinPortal width={400} position="top">
                  <HoverCard.Target>
                    <IconInfoCircle size={14} />
                  </HoverCard.Target>
                  <HoverCard.Dropdown>
                    <Typography variant="body-lg">
                      Set the Network so that TiDB Cloud can connect to your MySQL server. Refer to{' '}
                      <a
                        href="https://docs.pingcap.com/tidbcloud/changefeed-sink-to-mysql/?plan=premium"
                        target="_blank"
                        rel="noreferrer"
                      >
                        documentation
                      </a>{' '}
                      for more details.
                    </Typography>
                  </HoverCard.Dropdown>
                </HoverCard>
              </Group>
            </Input.Label>
          }
          data={connectionMethods}
          disabled={isEditing}
        />

        {isPrivateLink ? (
          <>
            <Group align="flex-start">
              <FormSelect
                label="Private Endpoint"
                data={privateEndpointOptions}
                disabled={isEditing}
                rules={{
                  required: 'Required',
                  validate: () => true
                }}
                name="network_info.sink_endpoint_id"
                placeholder="Select a Private Endpoint"
                description={
                  <Input.Description>
                    Didn't find one?{' '}
                    <Box component="a" onClick={privateEndpointHandler.open}>
                      Create a Private Endpoint here
                    </Box>
                  </Input.Description>
                }
                rightSection={isLoading ? <Loader size="xs" /> : null}
                inputWrapperOrder={['label', 'input', 'description', 'error']}
                sx={{ flex: 1 }}
              />

              <FormTextInput
                name="ports_str"
                label="Port"
                disabled={isEditing}
                rules={{
                  required: 'Required'
                }}
                placeholder="Enter the port of your MySQL database, i.e. 3306"
                inputWrapperOrder={['label', 'input', 'description', 'error']}
                onChange={(e) => {
                  const ports = Array.from(
                    new Set(
                      e.target.value
                        .split(',')
                        .map((i: string) => Number(i.trim()))
                        .filter((i) => !isNaN(i))
                    )
                  )
                  setValue('network_info.ports', ports)
                }}
                sx={{ flex: 1 }}
              />
            </Group>
          </>
        ) : (
          <>
            <FormTextInput
              label="MySQL Endpoint"
              name="mysql_info.connection.endpoint"
              rules={{
                required: 'Required'
              }}
              disabled={isEditing}
              placeholder="Enter the downstream MySQL endpoints, e.g 10.0.0.1:3306"
            />
          </>
        )}

        <Modal
          title="Create Private Endpoint for External Services"
          opened={privateEndpointOpened}
          onClose={privateEndpointHandler.close}
          size="xl"
          closeOnClickOutside={false}
        >
          <CreatePrivateEndpointForChangefeed
            cluster={cluster}
            onSuccess={(id) => {
              setValue('network_info.sink_endpoint_id', id)
            }}
            onCancel={() => {
              privateEndpointHandler.close()
              refetch()
            }}
          />
        </Modal>
      </Stack>

      <Divider />

      <Stack m={24} gap={8} maw={1000}>
        <HeadLabel label="Authentication" />

        <Group grow align="flex-start">
          <FormTextInput
            name="mysql_info.connection.username"
            label="User Name"
            rules={{ required: 'Required' }}
            placeholder="Enter the user name of your MySQL database"
          />

          <FormPasswordInput
            name="mysql_info.connection.password"
            label="Password"
            placeholder="Enter the password of your MySQL database"
            rules={isEditing ? undefined : { required: 'Required' }}
          />
        </Group>
      </Stack>
    </>
  )
}
