import {
  Anchor,
  Button,
  Card,
  Collapse,
  Group,
  HoverCard,
  Image,
  Modal,
  Stack,
  TextInput,
  Typography
} from '@tidbcloud/uikit'
import { FormPasswordInput, FormRadioGroup, FormTextInput } from '@tidbcloud/uikit/biz'
import { useDisclosure } from '@tidbcloud/uikit/hooks'
import { IconChevronDown, IconChevronUp } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import type { ReactNode } from 'react'
import { useEffect, useState } from 'react'
import type { RegisterOptions } from 'react-hook-form'
import { useFormContext } from 'react-hook-form'

import { CopyButton } from 'dbaas/components/CopyButton'
import { useGetCurrentClusterDataIngestionProfile } from 'dbaas/features/Common'

import step1 from './images/s3-step1.png'
import step2 from './images/s3-step2.png'

interface S3BucketAccessProps {
  bucketUri: string
  bucketUriName: string
  authTypeFormName: string
  roleArnFormName: string
  accessKeyFormName: string
  accessKeySecretFormName: string
  cloudformationTemplateUrl: string
  cloudformationStackName: string
  roleArnDocLink: string
  accessKeyDocLink: string
  supportedMethods?: ('manual' | 'access_key')[]
  label?: string
  pathHashUrl?: string
  roleArnOptionName?: string
  accessKeyOptionName?: string
  awsAccountIdVal?: string | undefined
  awsExternalIdVal?: string | undefined
  requireBucketUriForRoleArn?: boolean
  bucketUriMissingMessage?: ReactNode
  accessKeySecretRules?: RegisterOptions
}

function _S3BucketAccess({
  bucketUri,
  bucketUriName,
  authTypeFormName,
  roleArnFormName,
  accessKeyFormName,
  accessKeySecretFormName,
  cloudformationTemplateUrl,
  cloudformationStackName,
  roleArnDocLink,
  accessKeyDocLink,
  supportedMethods = ['manual', 'access_key'],
  label = 'Bucket Access',
  pathHashUrl = 'stacks/create/review',
  roleArnOptionName = 'manual',
  accessKeyOptionName = 'access_key',
  awsAccountIdVal,
  awsExternalIdVal,
  requireBucketUriForRoleArn = false,
  bucketUriMissingMessage,
  accessKeySecretRules = { required: 'Required' }
}: S3BucketAccessProps) {
  const { setValue, watch } = useFormContext()
  const [isModalOpen, { open: openModal, close: closeModal }] = useDisclosure()
  const [newRoleArnInput, setNewRoleArnInput] = useState('')
  const accessType = watch(authTypeFormName) as typeof roleArnOptionName | typeof accessKeyOptionName
  const [opened, setOpened] = useState(false)
  const [showBucketUriMissing, setShowBucketUriMissing] = useState(false)

  const { data } = useGetCurrentClusterDataIngestionProfile()
  const awsAccountId = data?.awsAccountId
  const awsExternalId = data?.awsExternalId
  const s3Arn = `arn:aws:s3:::${bucketUri?.replace('s3://', '') + (bucketUri?.endsWith('/') ? '*' : '')}`

  const onOpenRoleArnModal = () => {
    if (requireBucketUriForRoleArn && !bucketUri?.trim()) {
      setShowBucketUriMissing(true)
      return
    }

    setShowBucketUriMissing(false)
    openModal()
  }

  useEffect(() => {
    if (showBucketUriMissing && bucketUri?.trim()) {
      setShowBucketUriMissing(false)
    }
  }, [bucketUri, showBucketUriMissing])

  return (
    <Stack>
      <FormRadioGroup
        name={authTypeFormName}
        data={[
          {
            label: 'AWS Role ARN',
            value: roleArnOptionName
          },
          {
            label: 'AWS Access Key',
            value: accessKeyOptionName
          }
        ]}
        label={label}
        defaultValue={roleArnOptionName}
        sx={{
          display: supportedMethods.length < 2 ? 'none' : 'block'
        }}
      />

      {accessType === roleArnOptionName && (
        <FormTextInput
          name={roleArnFormName}
          label="Role ARN"
          inputWrapperOrder={['label', 'input', 'description', 'error']}
          rules={{ required: 'Required' }}
          description={
            <span>
              Not sure what is Role ARN?{' '}
              <a onClick={onOpenRoleArnModal}>Click here to create new one with AWS CloudFormation.</a>
            </span>
          }
          placeholder="ARN of AWS IAM Role"
        />
      )}

      {showBucketUriMissing && bucketUriMissingMessage}

      {accessType === accessKeyOptionName && (
        <Group gap={16} grow>
          <FormTextInput
            name={accessKeyFormName}
            label="Access Key ID"
            rules={{ required: 'Required' }}
            placeholder="Enter Access Key ID"
            description={
              accessKeyDocLink ? (
                <span>
                  Not sure what is Access Key ID?{' '}
                  <a target="_blank" href={accessKeyDocLink} rel="noopener noreferrer">
                    Click here to learn how to create an AWS Access Key.
                  </a>
                </span>
              ) : undefined
            }
            inputWrapperOrder={['label', 'input', 'description', 'error']}
          />
          <FormPasswordInput
            rules={accessKeySecretRules}
            name={accessKeySecretFormName}
            label="Secret Access Key"
            placeholder="Enter Secret Access Key "
          />
        </Group>
      )}

      <Modal centered title="Add New Role ARN" opened={isModalOpen} onClose={closeModal} size={732}>
        <Stack gap={16}>
          <Typography variant="body-lg">
            Open the{' '}
            {bucketUri ? (
              <a
                href={`https://us-west-2.console.aws.amazon.com/cloudformation/home?region=us-west-2#/${pathHashUrl}?templateURL=${cloudformationTemplateUrl}&stackName=${cloudformationStackName}&param_TiDBCloudAccountId=${awsAccountIdVal ?? awsAccountId}&param_TiDBCloudExternalId=${awsExternalIdVal ?? awsExternalId}&param_S3ARN=${s3Arn}`}
                target="_blank"
                rel="noreferrer"
              >
                AWS Console with CloudFormation Template
              </a>
            ) : (
              <HoverCard>
                <HoverCard.Target>
                  <Typography variant="body-lg" span sx={{ cursor: 'pointer' }} c="carbon.6">
                    AWS Console with CloudFormation Template
                  </Typography>
                </HoverCard.Target>
                <HoverCard.Dropdown maw={360}>
                  Please enter the {bucketUriName} to get an actionable CloudFormation Template.
                </HoverCard.Dropdown>
              </HoverCard>
            )}
            , enter the role name, then scroll down and acknowledge to create a new role, and click on 'Create stack'.
          </Typography>

          <Image src={step1} />

          <Typography variant="body-lg">
            After the CloudFormation stack is created, go to the Outputs section of stack detail page to see the role
            ARN value.
          </Typography>

          <Image src={step2} />

          <Typography variant="body-lg">Copy and paste the Role ARN value below.</Typography>

          <Stack gap={4}>
            <TextInput
              value={newRoleArnInput}
              onChange={(e) => setNewRoleArnInput(e.target.value)}
              placeholder="Paste the Role ARN value here"
            />
          </Stack>

          <Group justify="space-between">
            <Anchor onClick={() => setOpened((o) => !o)}>
              <Group gap={4}>
                Having trouble? Create Role ARN manually
                {opened ? <IconChevronUp size={16} /> : <IconChevronDown size={16} />}
              </Group>
            </Anchor>

            <Group>
              <Button variant="default" onClick={closeModal}>
                Cancel
              </Button>
              <Button
                disabled={!newRoleArnInput}
                onClick={async () => {
                  setValue(roleArnFormName, newRoleArnInput)
                  closeModal()
                }}
              >
                Confirm
              </Button>
            </Group>
          </Group>

          <Collapse in={opened} mx={-24} mb={-24} mt={8} bg="carbon.2">
            <Stack p={24}>
              <Typography variant="body-lg">
                Refer to{' '}
                <a href={roleArnDocLink} target="_blank" rel="noopener noreferrer">
                  the manual guide
                </a>{' '}
                to configure the IAM role with the following two IDs.
              </Typography>
              <Stack gap={4}>
                <Typography variant="label-lg" fw={500}>
                  TiDB Cloud Account ID
                </Typography>
                <Card withBorder shadow="unset" p={0}>
                  <Group justify="space-between" pl={8}>
                    <Typography>{awsAccountIdVal || awsAccountId || ''}</Typography>
                    <CopyButton text={awsAccountIdVal || awsAccountId || ''} icon menuName="Import V3 AWS Account ID" />
                  </Group>
                </Card>
              </Stack>
              <Stack gap={4}>
                <Typography variant="label-lg" fw={500}>
                  TiDB Cloud External ID
                </Typography>
                <Card withBorder shadow="unset" p={0}>
                  <Group justify="space-between" pl={8}>
                    <Typography>{awsExternalIdVal || awsExternalId || ''}</Typography>
                    <CopyButton
                      text={awsExternalIdVal || awsExternalId || ''}
                      icon
                      menuName="Import V3 AWS External ID"
                    />
                  </Group>
                </Card>
              </Stack>
            </Stack>
          </Collapse>
        </Stack>
      </Modal>
    </Stack>
  )
}

export const S3BucketAccess = observer(_S3BucketAccess)

/**
 * s3 compatible, only access key supported
 */
export const AliyunBucketAccess = ({
  accessKeyFormName,
  accessKeySecretFormName,
  accessKeyDocLink
}: Pick<S3BucketAccessProps, 'accessKeyFormName' | 'accessKeySecretFormName' | 'accessKeyDocLink'>) => {
  return (
    <Stack>
      <FormTextInput
        name={accessKeyFormName}
        label="AccessKey ID"
        rules={{ required: 'Required' }}
        placeholder="Enter your AccessKey ID"
        description={
          <span>
            Not sure what is AccessKey pair?{' '}
            <a target="_blank" href={accessKeyDocLink} rel="noopener noreferrer">
              Click here to learn how to create an AccessKey pair for Alibaba Cloud OSS.
            </a>
          </span>
        }
        inputWrapperOrder={['label', 'input', 'description', 'error']}
      />
      <FormPasswordInput
        rules={{ required: 'Required' }}
        name={accessKeySecretFormName}
        label="AccessKey Secret"
        placeholder="Enter your AccessKey Secret"
      />
    </Stack>
  )
}
