import { Alert, Divider, Group, Stack, Typography } from '@tidbcloud/uikit'
import { FormPasswordInput, FormTextInput } from '@tidbcloud/uikit/biz'
import { IconAlertCircle } from '@tidbcloud/uikit/icons'
import { useEffect, useState } from 'react'
import { useFormContext } from 'react-hook-form'

import { useIsEditingChangefeed } from 'dbaas/features/Changefeed'
import { DataSourceType } from 'dbaas/features/Import'
import { validateAwsSecretAccessKey, validateBucketURI } from 'dbaas/features/Import/validator'
import { CloudProviderConst } from 'dbaas/features/Project'
import {
  getS3EndpointAuthType,
  normalizeS3Uri
} from 'dbaas/screens/Changefeed/CreateOrEditChangefeedPremium/step1/payloadBuilders'
import { S3BucketAccess } from 'dbaas/screens/Cluster/ImportV3/S3BucketAccess'
import { SharedTiDB } from 'dbaas/screens/NextGen/shared/model/shared-tidb-state'
import { DataflowS3AuthType, ConsoleapiS3Provider } from 'dbaas/services/dataflow/interface'

const getAliCloudOSSEndpoint = (regionId: string) => {
  const normalizedRegionId = regionId.replace(/^alicloud-/i, '')
  return `https://s3.oss-${normalizedRegionId}.aliyuncs.com`
}

export function FormS3({ cluster }: { cluster: SharedTiDB }) {
  const isEditing = useIsEditingChangefeed()
  const { setValue, watch } = useFormContext()
  const isAliCloud = cluster.cloudProvider === CloudProviderConst.ALICLOUD
  const authType = watch('s3_info.endpoint.auth_type') as DataflowS3AuthType
  const accessKey = watch('s3_info.endpoint.access_key') as string
  const secretKey = watch('s3_info.endpoint.secret_key') as string
  const s3Uri = watch('s3_info.endpoint.s3Uri') as string
  const normalizedS3Uri = normalizeS3Uri(s3Uri)
  const [initialAuthType] = useState(
    () =>
      getS3EndpointAuthType({
        auth_type: authType,
        access_key: accessKey,
        secret_key: secretKey
      }) as DataflowS3AuthType
  )
  const [initialAccessKey] = useState(() => accessKey ?? '')
  const [stackName] = useState(() => `TiDBCloud-Changefeed-${Date.now()}`)
  const canKeepExistingAccessKeySecret =
    isEditing && initialAuthType === DataflowS3AuthType.S3_AUTH_TYPE_AK_SK && accessKey === initialAccessKey

  useEffect(() => {
    if (isAliCloud) {
      setValue('s3_info.endpoint.auth_type', DataflowS3AuthType.S3_AUTH_TYPE_AK_SK)
      setValue('s3_info.endpoint.provider', ConsoleapiS3Provider.S3_PROVIDER_ALIBABA_OSS)
      setValue('s3_info.endpoint.endpoint', getAliCloudOSSEndpoint(cluster.regionId))
      return
    }

    if (authType) {
      return
    }

    setValue(
      's3_info.endpoint.auth_type',
      getS3EndpointAuthType({
        access_key: accessKey,
        secret_key: secretKey
      })
    )
  }, [accessKey, authType, cluster.regionId, isAliCloud, secretKey, setValue])

  const uriLabel = isAliCloud ? 'OSS URI' : 'S3 URI'
  const accessKeySecretRules = isAliCloud
    ? {
        validate: canKeepExistingAccessKeySecret ? () => true : (val?: string) => Boolean(val) || 'Required'
      }
    : {
        validate: canKeepExistingAccessKeySecret
          ? (val?: string) => {
              if (!val) return true
              return validateAwsSecretAccessKey(val)
            }
          : validateAwsSecretAccessKey
      }

  return (
    <>
      <Divider />
      <Stack m={24} maw={1000}>
        <FormTextInput
          name="s3_info.endpoint.s3Uri"
          rules={{
            validate: (val) =>
              validateBucketURI(val, {
                sourceType: isAliCloud ? DataSourceType.aliyun : DataSourceType.aws,
                directory: true,
                enforceDirectoryTrailingSlash: false
              })
          }}
          label={uriLabel}
          placeholder={isAliCloud ? 'oss://tidbcloud-data/incremental/' : 's3://tidbcloud-samples/data-ingestion/'}
          disabled={isEditing}
        />

        {isAliCloud ? (
          <Group gap={16} grow>
            <FormTextInput
              name="s3_info.endpoint.access_key"
              label="Access Key ID"
              rules={{ required: 'Required' }}
              placeholder="Enter Access Key ID"
            />
            <FormPasswordInput
              name="s3_info.endpoint.secret_key"
              label="Access Key Secret"
              rules={accessKeySecretRules}
              placeholder="Enter Access Key Secret"
            />
          </Group>
        ) : (
          <S3BucketAccess
            bucketUri={normalizedS3Uri ?? ''}
            bucketUriName={uriLabel}
            authTypeFormName="s3_info.endpoint.auth_type"
            roleArnFormName="s3_info.endpoint.iam_assumed_role_arn"
            accessKeyFormName="s3_info.endpoint.access_key"
            accessKeySecretFormName="s3_info.endpoint.secret_key"
            cloudformationTemplateUrl="https://tidbcloud-prod-public-cloudformation-templates.s3.us-west-2.amazonaws.com/changefeed-role-aws.json"
            cloudformationStackName={stackName}
            roleArnDocLink="https://docs.pingcap.com/tidbcloud/dedicated-external-storage/#configure-amazon-s3-access-using-a-role-arn"
            accessKeyDocLink=""
            label="Bucket Access"
            pathHashUrl="stacks/quickcreate"
            roleArnOptionName={DataflowS3AuthType.S3_AUTH_TYPE_ASSUME_ROLE}
            accessKeyOptionName={DataflowS3AuthType.S3_AUTH_TYPE_AK_SK}
            accessKeySecretRules={accessKeySecretRules}
            requireBucketUriForRoleArn
            bucketUriMissingMessage={
              <Alert icon={<IconAlertCircle />} color="yellow">
                Please fill in the {uriLabel} and try again.
              </Alert>
            }
          />
        )}

        {isAliCloud && (
          <Typography>
            See{' '}
            <a
              href="https://docs.pingcap.com/tidbcloud/changefeed-sink-to-cloud-storage/?plan=premium"
              target="_blank"
              rel="noreferrer"
            >
              how to sink to cloud storage
            </a>
            .
          </Typography>
        )}

        {!isAliCloud && authType === DataflowS3AuthType.S3_AUTH_TYPE_AK_SK && (
          <Alert icon={<IconAlertCircle />}>
            Using Access Key/Secret Key (AK/SK) means you need to manage and rotate credentials manually, and there is a
            higher risk of accidental exposure. For simpler management and better security, we recommend using a Role
            ARN instead.
          </Alert>
        )}
      </Stack>
    </>
  )
}
