import { TextFileUploadProps } from '@tidb-cloud/ui-components'
import { Alert, Button, Card, Divider, Group, Stack } from '@tidbcloud/uikit'
import { IconAlertCircle } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useMemo, useRef, useState } from 'react'
import { useFormContext } from 'react-hook-form'

import { FormErrorMessage } from 'dbaas/components/Form'
import { useProgressModal } from 'dbaas/screens/DataImportV2/useProgressModal'
import {
  migrationServiceValidateMigrationSourceConn,
  migrationServiceValidateMigrationTargetConn
} from 'dbaas/services/api-clients/legacy/serverless'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import ConnectPreparationModal from './ConnectPreparationModal'
import { FormEssentialSourceConnection } from './FormEssentialSourceConnection'
import { FormJobName } from './FormJobName'
import { FormTargetConnection } from './FormTargetConnection'
import { buildEssentialConnProfile, useGetIpWhiteList } from './helper'

export interface EssentialStep1FormData {
  name: string
  data_source: string
  connect_method: string
  connect_method_display_name: string
  host?: string
  service_endpoint?: string
  endpoint_id?: string
  port: number
  ssl: boolean
  username: string
  password: string
  cluster_username: string
  cluster_password: string
  ssl_ca?: string
  ssl_cert?: string
  ssl_key?: string
  ssl_ca_value?: TextFileUploadProps['value']
  ssl_cert_value?: TextFileUploadProps['value']
  ssl_key_value?: TextFileUploadProps['value']
}

const Step1 = ({ onCancel, onFinish }: { onFinish: () => void; onCancel: () => void }) => {
  const {
    store: { tenantData, activeProjectId, currentCluster }
  } = useStores()
  const [confirmOpen, setConfirmOpen] = useState(false)

  const [loading, setLoading] = useState(false)
  const { watch, handleSubmit, getValues } = useFormContext<EssentialStep1FormData>()
  const connMethod = watch('connect_method') ?? ''

  const isPrivateConnect = useMemo(() => connMethod.toLowerCase().includes('private'), [connMethod])
  const ipWhitelist = useGetIpWhiteList({
    connMethod,
    isDedicated: !!currentCluster?.computed.isDedicated,
    isEssential: !!currentCluster?.computed.isEssential
  })

  const abortControllerRef = useRef<AbortController>()
  const [errorMessage, setErrorMessage] = useState('')
  const [validateConnectionError, setValidateConnectionError] = useState<{
    target: string
    source: string
  }>({
    target: '',
    source: ''
  })
  const progress = useProgressModal({
    error:
      errorMessage || [validateConnectionError.source, validateConnectionError.target].filter(Boolean).join('<br/>'),
    title: 'Validating',
    onCancel: () => abortControllerRef.current?.abort()
  })

  const onSubmit = async (data: EssentialStep1FormData) => {
    eventTracking('Validate DataMigration job connections started', {
      connect_method: data.connect_method_display_name
    })
    if (data.ssl) {
      if (!data.ssl_ca_value && !data.ssl_cert_value && !data.ssl_key_value) {
        setErrorMessage('SSL certificate is needed if you use SSL.')
        return
      }

      if ((data.ssl_cert_value && !data.ssl_key_value) || (!data.ssl_cert_value && data.ssl_key_value)) {
        setErrorMessage('Client certificate and Client private key should be provided at the same time.')
        return
      }
    }

    if (!isPrivateConnect) {
      setConfirmOpen(true)
      return
    }

    onDone()
  }

  const onDone = async () => {
    setConfirmOpen(false)
    const data = getValues() as EssentialStep1FormData
    setErrorMessage('')
    setLoading(true)
    setValidateConnectionError({ target: '', source: '' })
    progress.start()
    const controller = new AbortController()
    abortControllerRef.current = controller
    const errors: string[] = []

    const requestOptions = { signal: controller.signal, timeout: 60 * 1000 }

    const results = await Promise.allSettled([
      migrationServiceValidateMigrationTargetConn(
        tenantData.id,
        activeProjectId,
        currentCluster?.id!,
        {
          user: data.cluster_username,
          password: data.cluster_password
        },
        requestOptions
      ),
      migrationServiceValidateMigrationSourceConn(
        tenantData.id,
        activeProjectId,
        currentCluster?.id!,
        {
          conn_profile: buildEssentialConnProfile({
            connect_method: data.connect_method,
            endpoint_id: data.endpoint_id,
            host: data.host || data.service_endpoint,
            port: data.port,
            username: data.username,
            password: data.password,
            ssl: data.ssl,
            ssl_ca: data.ssl_ca,
            ssl_cert: data.ssl_cert,
            ssl_key: data.ssl_key
          })
        },
        requestOptions
      )
    ])

    if (results[0].status === 'rejected') {
      const reason = getErrorMessage(results[0].reason, true)
      errors.push(reason)
      setValidateConnectionError((prev) => ({
        ...prev,
        target: reason
      }))
    }
    if (results[1].status === 'rejected') {
      const reason = getErrorMessage(results[1].reason, true)
      errors.push(reason)
      setValidateConnectionError((prev) => ({
        ...prev,
        source: reason
      }))
    }

    setLoading(false)

    if (errors.length > 0) {
      eventTracking('Validating DataMigration job connections failed', {
        connect_method: data.connect_method_display_name
      })
      progress.pause()
    } else {
      eventTracking('Validating DataMigration job connections succeed', {
        connect_method: data.connect_method_display_name
      })
      progress.done()
      onFinish()
    }
  }

  return (
    <Card p={0}>
      <form onSubmit={handleSubmit((values) => onSubmit(values as EssentialStep1FormData))}>
        <FormJobName />

        <Divider />

        <FormEssentialSourceConnection />

        <Divider />

        <FormTargetConnection isPrivate={isPrivateConnect} cluster={currentCluster} />

        <Divider />

        <Stack m={24}>
          {!progress.isOpen && <FormErrorMessage message={errorMessage} autoScroll />}

          {validateConnectionError.target && (
            <Alert title="Connect to target failed" icon={<IconAlertCircle />} color="red">
              {validateConnectionError.target}
            </Alert>
          )}

          {validateConnectionError.source && (
            <Alert title="Connect to source failed" icon={<IconAlertCircle />} color="red">
              {validateConnectionError.source}
            </Alert>
          )}

          <Group justify="flex-end">
            <Button
              variant="default"
              type="button"
              onClick={onCancel}
              data-mp-event="Cancel on Data Migration Creation Step 1 Clicked"
            >
              Cancel
            </Button>
            <Button type="submit" loading={loading} data-mp-event="Submit on Data Migration Creation Step 1 Clicked">
              Validate Connection and Next
            </Button>
          </Group>
        </Stack>
      </form>

      {progress.content}

      <ConnectPreparationModal
        opened={confirmOpen}
        onClose={() => setConfirmOpen(false)}
        onContinue={onDone}
        ipWhitelist={ipWhitelist}
      />
    </Card>
  )
}

export const EssentialDMStep1 = observer(Step1)
