import { TextFileUpload } from '@tidb-cloud/ui-components'
import { Box, Grid, Group, HoverCard, Input, List, Loader, Modal, Stack, Typography } from '@tidbcloud/uikit'
import {
  FormNumberInput,
  FormPasswordInput,
  FormSelect,
  FormSwitch,
  FormTextInput,
  LabelTooltip
} from '@tidbcloud/uikit/biz'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconInfoCircle } from '@tidbcloud/uikit/icons'
import { useMemo } from 'react'
import { Controller, useFormContext } from 'react-hook-form'
import { Link } from 'react-router-dom'

import { CreatePrivateEndpointForChangefeed } from 'dbaas/screens/NextGen/premium/networking/private-endpoint-changefeed/Create'
import { useSharedTiDBContextSafe } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/tidb-context'
import { useNgListSinkEndpoints } from 'dbaas/services/dataflow'

import { useListSupportedSources } from './helper'

export const FormSourceConnection = () => {
  const { control, watch, setValue } = useFormContext()
  const tidb = useSharedTiDBContextSafe()
  const source = watch('data_source')
  const connMethod = watch('connect_method') ?? ''
  const ssl = watch('ssl')
  const { sourceOptions, connOptions, getConnOptions, isLoading: isLoadingSources } = useListSupportedSources(source)
  const isPrivateConnect = useMemo(() => connMethod.toLowerCase().includes('private'), [connMethod])
  const shouldUseSinkEndpointSelect = Boolean(
    (tidb?.computed.isPremium || tidb?.computed.isPremiumReserved || tidb?.computed.isEssentialV2) && isPrivateConnect
  )
  const isAzureMysql = useMemo(() => source?.toLowerCase().includes('azure') ?? false, [source])
  const [privateEndpointOpened, privateEndpointHandler] = useDisclosure()

  const {
    data: privateEndpointData,
    isLoading: isLoadingPrivateEndpoints,
    refetch: refetchPrivateEndpoints
  } = useNgListSinkEndpoints(
    tidb?.tidbId ?? '',
    {
      status: 'SINK_ENDPOINT_STATUS_AVAILABLE'
    },
    {
      query: {
        enabled: shouldUseSinkEndpointSelect && !!tidb?.tidbId,
        refetchOnMount: false,
        refetchOnWindowFocus: false
      }
    }
  )
  const privateEndpointOptions = useMemo(() => {
    return (
      privateEndpointData?.sink_endpoints?.map((endpoint) => ({
        label: endpoint.endpoint_name!,
        value: endpoint.id!
      })) ?? []
    )
  }, [privateEndpointData])

  const closePrivateEndpointModal = () => {
    privateEndpointHandler.close()
    refetchPrivateEndpoints()
  }

  return (
    <Stack m={24} gap={8}>
      <Typography variant="headline-sm">Source Connection Profile</Typography>

      <Grid>
        <Grid.Col span={6}>
          <FormSelect
            name="data_source"
            data={sourceOptions}
            label="Data Source"
            rules={{ required: 'Required' }}
            placeholder="Select database engine"
            disabled={isLoadingSources}
            rightSection={isLoadingSources ? <Loader size={'xs'} /> : undefined}
            onChange={(val) => {
              setValue('sink_endpoint_id', '')
              setValue('sink_endpoint_name', '')
              // if source changed, reset conn method when needed
              if (val) {
                const options = getConnOptions(val)
                if (options.findIndex((i) => i.value === connMethod) === -1) {
                  const option = options[0]
                  setValue('connect_method', option?.value ?? '')
                  setValue('connect_method_display_name', option?.label ?? '')
                }
              }
            }}
          />
        </Grid.Col>

        <Grid.Col span={6}>
          <FormSelect
            name="connect_method"
            data={connOptions}
            label="Connectivity Method"
            rules={{ required: 'Required' }}
            placeholder="Select connect method"
            inputWrapperOrder={['label', 'input', 'description', 'error']}
            description={
              connMethod.toLowerCase().includes('vpc') ? (
                <span>
                  If not configured yet, please configure{' '}
                  <Link to="/project/network-access/vpc-peerings" target="_blank">
                    VPC Peering
                  </Link>{' '}
                  first.
                </span>
              ) : undefined
            }
            onChange={(val) => {
              setValue('connect_method_display_name', connOptions.find((i) => i.value === val)?.label!)
              setValue('sink_endpoint_id', '')
              setValue('sink_endpoint_name', '')
            }}
          />

          <Controller
            name="connect_method_display_name"
            control={control}
            render={({ field }) => <input {...field} hidden />}
          />
        </Grid.Col>

        <Grid.Col span={6}>
          {isPrivateConnect ? (
            shouldUseSinkEndpointSelect ? (
              <FormSelect
                name="sink_endpoint_id"
                key="sink_endpoint_id"
                label="Private Endpoint"
                data={privateEndpointOptions}
                rules={{ required: 'Required' }}
                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={isLoadingPrivateEndpoints ? <Loader size="xs" /> : null}
                inputWrapperOrder={['label', 'input', 'description', 'error']}
                onChange={(val) => {
                  const option = privateEndpointOptions.find((item) => item.value === val)
                  setValue('sink_endpoint_name', option?.label ?? '')
                }}
              />
            ) : isAzureMysql ? (
              <FormTextInput
                name="service_endpoint"
                key="azure_service_endpoint"
                label={
                  <Group gap={8}>
                    <Input.Label mb={0}>Azure MySQL Flexible Server Resource ID</Input.Label>

                    <HoverCard>
                      <HoverCard.Target>
                        <IconInfoCircle />
                      </HoverCard.Target>
                      <HoverCard.Dropdown maw={400}>
                        Follow the steps below to learn how to find the Resource ID:
                        <Box component={List} px={8} py={8}>
                          <List.Item>
                            Azure Portal → Azure Database for MySQL Flexible Server → Overview → JSON View.
                          </List.Item>
                          <List.Item sx={{ wordBreak: 'break-all' }}>
                            {`Copy the value of the id property (format /subscriptions/<...>/resourceGroups/<...>/providers/Microsoft.DBforMySQL/flexibleServers/<server>).`}
                          </List.Item>
                        </Box>
                      </HoverCard.Dropdown>
                    </HoverCard>
                  </Group>
                }
                rules={{
                  required: 'Required',
                  pattern: {
                    value:
                      /^\/subscriptions\/[a-fA-F0-9-]+\/resourceGroups\/[a-zA-Z0-9_.-]+\/providers\/Microsoft\.DBforMySQL\/flexibleServers\/[a-zA-Z0-9-]+$/,
                    message: 'Invalid format'
                  }
                }}
                inputWrapperOrder={['label', 'input', 'description', 'error']}
                placeholder="Enter the Azure MySQL Flexible Server Resource ID"
              />
            ) : (
              <FormTextInput
                name="service_endpoint"
                key="service_endpoint"
                label="Endpoint Service Name"
                rules={{ required: 'Required' }}
                placeholder="Enter the endpoint service name"
              />
            )
          ) : (
            <FormTextInput
              name="host"
              key="host"
              label="Hostname or IP address"
              rules={{ required: 'Required' }}
              placeholder="Enter hostname or IP address"
            />
          )}
        </Grid.Col>

        <Grid.Col span={6}>
          <FormNumberInput name="port" label="Port" placeholder="Enter port number" />
        </Grid.Col>

        <Grid.Col span={6}>
          <FormTextInput
            name="username"
            label="User Name"
            inputWrapperOrder={['label', 'input', 'description', 'error']}
            description={
              <span>
                Please refer to the{' '}
                <a
                  tabIndex={-1}
                  href="https://docs.pingcap.com/tidbcloud/migrate-from-mysql-using-data-migration/#grant-required-privileges-for-migration"
                  target="_blank"
                  rel="noreferrer"
                >
                  documentation
                </a>{' '}
                for the required privileges
              </span>
            }
            placeholder="Enter your source user name"
          />
        </Grid.Col>

        <Grid.Col span={6}>
          <FormPasswordInput name="password" label="Password" placeholder="Enter your password" />
        </Grid.Col>

        <Grid.Col span={12}>
          <Group wrap="nowrap" h={56}>
            <Stack gap={4} mr={32}>
              <Group gap={4}>
                <Typography variant="label-lg">SSL/TLS</Typography>
                <LabelTooltip
                  label={
                    <Typography variant="body-md">
                      Choose from the following 3 certificate combinations:
                      <Typography>1. CA Certificate, Client Certificate, Client Private Key</Typography>
                      <Typography>2. Client Certificate, Client Private Key</Typography>
                      <Typography>3. CA Certificate</Typography>
                      Then upload the necessary certificates based on your requirements.
                    </Typography>
                  }
                />
              </Group>
              <FormSwitch name="ssl" pt={10} />
            </Stack>

            {ssl && (
              <>
                <Stack gap={4}>
                  <Typography variant="label-lg">CA Certificate</Typography>
                  <Controller
                    name="ssl_ca_value"
                    control={control}
                    render={({ field }) => (
                      <TextFileUpload
                        hideButtonAfterUpload
                        onChange={(value) => {
                          field.onChange(value)
                          setValue('ssl_ca', value?.content ?? '')
                        }}
                      />
                    )}
                  />
                </Stack>

                <Stack gap={4}>
                  <Typography variant="label-lg">Client Certificate</Typography>
                  <Controller
                    name="ssl_cert_value"
                    control={control}
                    render={({ field }) => (
                      <TextFileUpload
                        hideButtonAfterUpload
                        onChange={(value) => {
                          field.onChange(value)
                          setValue('ssl_cert', value?.content ?? '')
                        }}
                      />
                    )}
                  />
                </Stack>

                <Stack gap={4}>
                  <Typography variant="label-lg">Client private key</Typography>
                  <Controller
                    name="ssl_key_value"
                    control={control}
                    render={({ field }) => (
                      <TextFileUpload
                        hideButtonAfterUpload
                        onChange={(value) => {
                          field.onChange(value)
                          setValue('ssl_key', value?.content ?? '')
                        }}
                      />
                    )}
                  />
                </Stack>
                <Controller name="ssl_ca" control={control} render={({ field }) => <input {...field} hidden />} />
                <Controller name="ssl_cert" control={control} render={({ field }) => <input {...field} hidden />} />
                <Controller name="ssl_key" control={control} render={({ field }) => <input {...field} hidden />} />
              </>
            )}
          </Group>
        </Grid.Col>
      </Grid>

      {tidb && (
        <Modal
          title="Create Private Endpoint for External Services"
          opened={privateEndpointOpened}
          onClose={closePrivateEndpointModal}
          size="xl"
          closeOnClickOutside={false}
        >
          <CreatePrivateEndpointForChangefeed
            cluster={tidb}
            onSuccess={(id, name) => {
              setValue('sink_endpoint_id', id)
              setValue('sink_endpoint_name', name ?? '')
            }}
            onCancel={closePrivateEndpointModal}
            trackingEvents={{
              cancel: 'Cancel creating private endpoint for Premium Data Migration',
              submit: 'Submit creating private endpoint for Premium Data Migration'
            }}
          />
        </Modal>
      )}
    </Stack>
  )
}
