import { Alert, Button, Card, Divider, Group, Stack, Typography } from '@tidbcloud/uikit'
import { FormErrorMessage, FormPasswordInput, FormSelect, FormTextInput } from '@tidbcloud/uikit/biz'
import { IconAlertCircle, IconCheckCircle } from '@tidbcloud/uikit/icons'
import { useMemoizedFn, useUpdateEffect } from 'ahooks'
import { useMemo, useState } from 'react'
import { useFormContext, useWatch } from 'react-hook-form'
import { useParams } from 'react-router-dom'

import {
  getBucketURIByImportSourceTypeServerless,
  AzureBlobStorageTemplateLinkForServerlessImport
} from 'dbaas/features/Import'
import { getImportStatusWithClusterStateCheckOnly } from 'dbaas/features/Import/useImportStatus'
import { CloudProviderConst, CloudStorageLabelConst } from 'dbaas/features/Project'
import { FormAzureSasTokenInput } from 'dbaas/screens/Cluster/ImportV3/AzureBlobAccess'
import { AliyunBucketAccess, S3BucketAccess } from 'dbaas/screens/Cluster/ImportV3/S3BucketAccess'
import { SharedTiDB } from 'dbaas/screens/NextGen/shared/model/shared-tidb-state'
import { Commonv1beta1ServicePlan } from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2/interface'
import { useCheckDatabaseConnectivity, useCheckImportSourceConnection } from 'dbaas/services/dataflow'
import { Adminapiv1beta2ImportSourceTypeEnum as PremiumImportSourceType } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import { eventTracking, MixpanelEvents } from 'dbaas/utils/tracking'

import { normalizeImportSource } from './helper'
import { ImportFromCloudFormData } from './types'

export type ConfigureConnectionFormData = {
  storage_provider: PremiumImportSourceType
  source_uri: string
  // azure connectivity method
  sasToken?: string
  s3_bucket_access_method: 'manual' | 'access_key'
  aws_role_arn?: string
  aws_access_key_id?: string
  aws_secret_access_key?: string
  aliyun_access_key_id?: string
  aliyun_secret_access_key?: string
  username?: string
  password?: string
}

export const ConfigureConnection = ({
  onCancel,
  onFinish,
  cluster
}: {
  onCancel: () => void
  onFinish: (data: any) => void
  cluster: SharedTiDB
}) => {
  const methods = useFormContext<ImportFromCloudFormData>()
  const sourceUri = methods.watch('source_uri')
  const storageProvider = methods.watch('storage_provider')
  const sourceVerificationFields = useWatch({
    control: methods.control,
    name: [
      'storage_provider',
      'source_uri',
      'sasToken',
      's3_bucket_access_method',
      'aws_role_arn',
      'aws_access_key_id',
      'aws_secret_access_key',
      'aliyun_access_key_id',
      'aliyun_secret_access_key'
    ]
  })
  const databaseVerificationFields = useWatch({
    control: methods.control,
    name: ['username', 'password']
  })
  const isS3 = storageProvider === PremiumImportSourceType.ENUM_S3
  const isAliyun = storageProvider === PremiumImportSourceType.ENUM_OSS
  const isAzure = storageProvider === PremiumImportSourceType.ENUM_AZURE_BLOB
  const isAliyunCluster = cluster?.cloudProvider === CloudProviderConst.ALICLOUD
  const isAzureCluster = cluster?.cloudProvider === CloudProviderConst.AZURE

  const stateCheckTips = getImportStatusWithClusterStateCheckOnly(cluster)
  const { id: tidbId } = useParams<{ id: string }>()

  const sourceTypeOptions = useMemo(() => {
    return [
      {
        label: CloudStorageLabelConst[CloudProviderConst.AWS],
        value: PremiumImportSourceType.ENUM_S3
      },
      {
        label: CloudStorageLabelConst[CloudProviderConst.ALICLOUD],
        value: PremiumImportSourceType.ENUM_OSS
      },
      ...(isAzureCluster
        ? [
            {
              label: CloudStorageLabelConst[CloudProviderConst.AZURE],
              value: PremiumImportSourceType.ENUM_AZURE_BLOB
            }
          ]
        : [])
    ]
  }, [isAzureCluster])

  const checkSourceAccessMutation = useCheckImportSourceConnection()
  const checkDatabaseConnection = useCheckDatabaseConnectivity()
  const [isSourceVerified, setIsSourceVerified] = useState(false)
  const [isDatabaseVerified, setIsDatabaseVerified] = useState(false)

  useUpdateEffect(() => {
    setIsSourceVerified(false)
    checkSourceAccessMutation.reset()
  }, sourceVerificationFields)

  useUpdateEffect(() => {
    setIsDatabaseVerified(false)
    checkDatabaseConnection.reset()
  }, databaseVerificationFields)

  const testBucketURIConnection = useMemoizedFn(async (): Promise<boolean> => {
    const fieldsToValidate: Array<keyof ImportFromCloudFormData> = [
      'aws_role_arn',
      'aws_access_key_id',
      'aws_secret_access_key',
      'source_uri',
      'aliyun_access_key_id',
      'aliyun_secret_access_key'
    ]

    if (storageProvider === PremiumImportSourceType.ENUM_AZURE_BLOB) {
      fieldsToValidate.push('sasToken')
    }

    const result = await methods.trigger(fieldsToValidate)
    if (!result) {
      setIsSourceVerified(false)
      return false
    }

    const data = methods.getValues()
    const source = normalizeImportSource(data)
    if (!source) {
      setIsSourceVerified(false)
      return false
    }

    try {
      const response = await checkSourceAccessMutation.mutateAsync({
        tidbId,
        data: { source }
      })

      const isConnected = !!response.success
      setIsSourceVerified(isConnected)

      return isConnected
    } catch (error) {
      setIsSourceVerified(false)
      eventTracking(MixpanelEvents.TidbImportTestConnect.Run.RequestFailed, {
        servicePlan: Commonv1beta1ServicePlan.Premium,
        target: 'Bucket',
        error: getErrorMessage(error)
      })
      return false
    }
  })

  const testDatabaseConnection = useMemoizedFn(async (): Promise<boolean> => {
    const result = await methods.trigger(['username', 'password'])
    if (!result) {
      setIsDatabaseVerified(false)
      return false
    }

    const data = methods.getValues()
    try {
      const response = await checkDatabaseConnection.mutateAsync({
        tidbId,
        data: {
          username: data.username,
          password: data.password
        }
      })

      const isConnected = !!response.success
      setIsDatabaseVerified(isConnected)

      return isConnected
    } catch (error) {
      setIsDatabaseVerified(false)
      const msg = getErrorMessage(error, true)
      eventTracking(MixpanelEvents.TidbImportTestConnect.Run.RequestFailed, {
        servicePlan: Commonv1beta1ServicePlan.Premium,
        target: 'Database',
        error: msg
      })
      return false
    }
  })

  const onSubmit = useMemoizedFn(async (data: ImportFromCloudFormData) => {
    const [isBucketConnected, isDatabaseConnected] = await Promise.all([
      isSourceVerified ? Promise.resolve(true) : testBucketURIConnection(),
      isDatabaseVerified ? Promise.resolve(true) : testDatabaseConnection()
    ])

    if (!isBucketConnected || !isDatabaseConnected) {
      return
    }

    onFinish(data)
  })

  const isNextDisabled = !!stateCheckTips

  return (
    <Card p={24}>
      <Stack component="form" onSubmit={methods.handleSubmit(onSubmit)}>
        <Typography variant="title-lg">Source Connection</Typography>
        <Typography variant="body-lg" c="carbon.8" mt={-12}>
          You can import CSV, SQL, Parquet files, or{' '}
          <a href="https://docs.pingcap.com/tidb/stable/dumpling-overview/" target="_blank" rel="noopener noreferrer">
            Dumpling exports
          </a>{' '}
          (compressed or uncompressed). Target tables must be empty.
        </Typography>

        <FormSelect name="storage_provider" label="Storage Provider" data={sourceTypeOptions} />

        <FormTextInput
          name="source_uri"
          label={isAzure ? 'Folder URI' : 'Source Files URI'}
          placeholder={getBucketURIByImportSourceTypeServerless(storageProvider)}
          rules={{ required: 'Please enter the source files URI' }}
          description={
            <span>
              Enter the S3 path to the <b>top-level folder</b> containing your source files.
            </span>
          }
        />

        {isS3 && (
          <S3BucketAccess
            label="Credentials"
            authTypeFormName="s3_bucket_access_method"
            roleArnFormName="aws_role_arn"
            accessKeyFormName="aws_access_key_id"
            accessKeySecretFormName="aws_secret_access_key"
            bucketUri={sourceUri}
            bucketUriName="Source Files URI"
            cloudformationTemplateUrl="https://tidbcloud-prod-public-cloudformation-templates.s3.us-west-2.amazonaws.com/import-role.json"
            cloudformationStackName={`TiDBCloud-Import-${Date.now()}`}
            roleArnDocLink="https://docs.pingcap.com/tidbcloud/configure-external-storage-access/?plan=premium#configure-amazon-s3-access-using-a-role-arn"
            accessKeyDocLink="https://docs.pingcap.com/tidbcloud/configure-external-storage-access/?plan=premium#configure-amazon-s3-access-using-an-aws-access-key"
            supportedMethods={isAliyunCluster || isAzureCluster ? ['access_key'] : ['manual', 'access_key']}
          />
        )}

        {/* {isGCS && <FormGCSBucketAccessUploader name="gcs_credential" label="Credential" />} */}

        {isAzure && (
          <FormAzureSasTokenInput
            name="sasToken"
            label="SAS Token"
            rules={{ required: 'Required' }}
            docLink="https://docs.pingcap.com/tidbcloud/configure-external-storage-access/#configure-azure-blob-storage-access"
            templateLink={AzureBlobStorageTemplateLinkForServerlessImport}
          />
        )}

        {isAliyun && (
          <AliyunBucketAccess
            accessKeyFormName="aliyun_access_key_id"
            accessKeySecretFormName="aliyun_secret_access_key"
            accessKeyDocLink="https://docs.pingcap.com/tidbcloud/configure-external-storage-access/?plan=premium#configure-alibaba-cloud-object-storage-service-oss-access"
          />
        )}

        <div>
          <Button
            variant="default"
            type="button"
            onClick={() => testBucketURIConnection()}
            loading={checkSourceAccessMutation.isLoading}
          >
            Test Bucket Access
          </Button>
        </div>

        {isSourceVerified && (
          <Alert color="green" icon={<IconCheckCircle />}>
            Successfully connected to the source bucket.
          </Alert>
        )}

        {(checkSourceAccessMutation.isError || checkSourceAccessMutation.data?.success === false) && (
          <FormErrorMessage
            message={
              checkSourceAccessMutation.isError
                ? getErrorMessage(checkSourceAccessMutation.error, true)
                : checkSourceAccessMutation.data?.errorMsg || 'Failed to access source files, please try again later.'
            }
          />
        )}

        <Divider mx={-24} />

        <Typography variant="title-lg">Target Connection</Typography>

        <Card bg="carbon.2" withBorder={false}>
          <Typography>
            Enter the TiDB user credentials for this import job.
            <br />• If target tables already exist, they must be empty, and the user must have{' '}
            <b>SELECT, INSERT, UPDATE,</b> and <b>DELETE</b> privileges.
            <br />• If the job needs to create schemas, the user also requires <b>CREATE</b> and <b>INDEX</b> privileges
            (if indexes are created).
          </Typography>
        </Card>

        <Group wrap="nowrap" align="flex-start">
          <FormTextInput
            label="Username"
            name="username"
            placeholder="Enter your username"
            rules={{ required: 'Required' }}
            flex={1}
          />
          <FormPasswordInput
            label="Password"
            name="password"
            placeholder="Enter your password"
            rules={{ required: 'Required' }}
            flex={1}
          />
          <Button
            type="button"
            variant="default"
            maw={140}
            mt={26}
            loading={checkDatabaseConnection.isLoading}
            onClick={() => testDatabaseConnection()}
          >
            Test Connection
          </Button>
        </Group>

        {isDatabaseVerified && (
          <Alert color="green" icon={<IconCheckCircle />}>
            Successfully connected to the target database.
          </Alert>
        )}

        {(checkDatabaseConnection.isError || checkDatabaseConnection.data?.success === false) && (
          <FormErrorMessage
            message={
              checkDatabaseConnection.isError
                ? getErrorMessage(checkDatabaseConnection.error, true)
                : checkDatabaseConnection.data?.errorMsg ||
                  'Failed to connect to the target database, please try again later.'
            }
          />
        )}

        <Divider mx={-24} />

        {stateCheckTips && (
          <Alert color="yellow" icon={<IconAlertCircle />}>
            {stateCheckTips}
          </Alert>
        )}

        <Group justify="flex-end">
          <Button variant="default" onClick={onCancel}>
            Cancel
          </Button>
          <Button
            type="submit"
            disabled={isNextDisabled}
            loading={checkSourceAccessMutation.isLoading || checkDatabaseConnection.isLoading}
          >
            Next
          </Button>
        </Group>
      </Stack>
    </Card>
  )
}
