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

import { useOrgProjectClusterIds } from 'dbaas/features/Common'
import { usePrivateLinkConnectionServiceListPrivateLinkConnections } from 'dbaas/services/api-clients/legacy/serverless'

import { useListSupportedSources } from './helper'

const parseIPv4 = (value: string) => {
  const parts = value.trim().split('.')
  if (parts.length !== 4) {
    return null
  }

  const octets = parts.map((part) => {
    if (!/^\d+$/.test(part)) {
      return null
    }

    const octet = Number(part)
    return octet >= 0 && octet <= 255 ? octet : null
  })

  return octets.every((octet) => octet !== null) ? (octets as number[]) : null
}

const isRFC1918PrivateIPv4 = (value: string) => {
  const octets = parseIPv4(value)
  if (!octets) {
    return false
  }

  const [first, second] = octets
  return first === 10 || (first === 172 && second >= 16 && second <= 31) || (first === 192 && second === 168)
}

export const FormEssentialSourceConnection = () => {
  const { control, watch, setValue } = useFormContext()
  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 { orgId, projectId, clusterId } = useOrgProjectClusterIds()

  const { data: privateLinkConnections, isLoading: isLoadingPrivateLinkConnections } =
    usePrivateLinkConnectionServiceListPrivateLinkConnections(
      orgId,
      projectId,
      clusterId!,
      {
        page_size: 50,
        page_token: '1',
        state: 'ACTIVE'
      },
      {
        query: {
          enabled: isPrivateConnect && !!orgId && !!projectId && !!clusterId,
          refetchOnWindowFocus: false
        }
      }
    )

  const privateLinkOptions = useMemo(() => {
    return (
      privateLinkConnections?.private_link_connections?.map((connection) => ({
        label: connection.display_name,
        value: connection.private_link_connection_id!
      })) ?? []
    )
  }, [privateLinkConnections])

  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) => {
              // 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!)
            }}
          />

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

        <Grid.Col span={6}>
          {isPrivateConnect ? (
            <FormSelect
              name="endpoint_id"
              label="Private Link Connection"
              rules={{ required: 'Required' }}
              placeholder="Select a Private Link Connection"
              data={privateLinkOptions}
              rightSection={isLoadingPrivateLinkConnections ? <Loader size="xs" /> : null}
            />
          ) : (
            <FormTextInput
              name="host"
              key="host"
              label="Hostname or IP address"
              rules={{
                required: 'Required',
                validate: (value) =>
                  !isRFC1918PrivateIPv4(value) ||
                  'Private IP addresses are not supported for public connectivity. Use Private Link Connection or enter a public hostname/IP address.'
              }}
              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>
    </Stack>
  )
}
