import { Button, Group, Modal, Stack, Text } from '@tidbcloud/uikit'
import { useEffect, useMemo, useState } from 'react'

import { useCreatePrivateLinkEndpoint, useGetPrivateLinkEndpoint } from 'dbaas/services/dataflow'
import { GetPrivateLinkEndpointRespPhase } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'

import PrivateLinkMessage from './PrivateLinkMessage'

/**
 * PrivateLinkCheck
 *
 * Encapsulates the full Private Link (VPC Endpoint) creation + polling flow
 * used by Data Migration Step 1 when the user selects a private connectivity method.
 *
 * Behavior
 * - When `opened` first becomes true and there is no existing `privateLinkId`, it
 *   calls `useCreatePrivateLinkEndpoint` to create a new Private Endpoint for the
 *   current org/project/cluster. If `serviceName` (AWS Endpoint Service name) is
 *   provided, it is passed along; otherwise it is omitted.
 * - After creation, it starts polling the Private Endpoint status via
 *   `useGetPrivateLinkEndpoint` (every 3s) while the modal is open. When the
 *   phase becomes `Available`, it triggers `onClose()` then `onAvailable()` to let
 *   the parent proceed to connection validation.
 * - If the phase is `PendingAcceptance`, an "Already done, continue" button is
 *   shown to allow manual re-check after the user approves the pending request
 *   in their cloud provider (AWS PrivateLink or Azure Portal depending on
 *   `isAzureMysql`). Clicking the button performs a one-off refetch and proceeds
 *   if the phase is now `Available`.
 * - If creation fails, the error is normalized via `getErrorMessage` and delivered
 *   to the parent with `onError(message)`, and the modal is closed.
 *
 * Notes
 * - The component reads `orgId`, `projectId`, and `clusterId` from the global store.
 * - The `privateLinkId` is kept in component state and persists for the lifetime of
 *   this component. If the modal is closed and reopened without unmounting the
 *   component, a new Private Endpoint will NOT be created (it will reuse the
 *   same `privateLinkId`). Parent components that need a brand-new Private Link
 *   should unmount this component between attempts.
 * - `serviceName` is typically required for AWS PrivateLink flows; it can be left
 *   undefined for Azure depending on the backend behavior. UI messages adapt to
 *   AWS vs Azure via `isAzureMysql`.
 *
 * Props
 * - opened: Controls modal visibility and enables polling. When true and there is
 *   no existing `privateLinkId`, a create call is issued.
 * - onClose: Called when the modal should close (user cancel or when proceeding).
 * - onAvailable: Called once the Private Endpoint reaches `Available`.
 * - serviceName: Optional Endpoint Service name (AWS). Passed during creation and
 *   displayed in the guidance content when applicable.
 * - isAzureMysql: Toggles provider-specific guidance text.
 * - onError: Receives a human-readable error if creation fails.
 */
export const PrivateLinkCheck = ({
  opened,
  onClose,
  onAvailable,
  serviceName,
  isAzureMysql,
  onError
}: {
  opened: boolean
  onClose: () => void
  onAvailable: () => void
  serviceName?: string
  isAzureMysql: boolean
  onError?: (msg: string) => void
}) => {
  const {
    store: { tenantData, activeProjectId, currentCluster }
  } = useStores()

  const [privateLinkId, setPrivateLinkId] = useState<string>()
  const [loading, setLoading] = useState(false)
  const createPlMutation = useCreatePrivateLinkEndpoint()

  const { data: privateLinkData, refetch } = useGetPrivateLinkEndpoint(
    tenantData.id,
    activeProjectId,
    currentCluster?.id!,
    privateLinkId!,
    {
      query: {
        enabled: Boolean(privateLinkId) && opened,
        refetchInterval: 3000,
        onSuccess(data) {
          if (data.phase === GetPrivateLinkEndpointRespPhase.Available && opened) {
            onClose()
            onAvailable()
          }
        }
      }
    }
  )

  useEffect(() => {
    if (!opened) return
    if (privateLinkId) return
    ;(async () => {
      try {
        const { id } = await createPlMutation.mutateAsync({
          orgId: tenantData.id,
          projectId: activeProjectId,
          clusterId: currentCluster?.id!,
          data: {
            endpoint_service_name: serviceName || undefined
          }
        })
        setPrivateLinkId(id)
        await refetch()
      } catch (e) {
        const msg = getErrorMessage(e)
        onError?.(msg)
        onClose()
      }
    })()
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [opened, serviceName])

  const onConfirmContinue = async () => {
    setLoading(true)
    const res = await refetch()
    setLoading(false)
    const phase = res.data?.phase
    if (phase === GetPrivateLinkEndpointRespPhase.Available) {
      onClose()
      onAvailable()
    }
  }

  const modalTitle = useMemo(() => {
    if (privateLinkData?.phase === GetPrivateLinkEndpointRespPhase.PendingAcceptance) {
      return 'Approve the pending Private Endpoint request'
    }
    if (privateLinkData?.phase === GetPrivateLinkEndpointRespPhase.Failed) {
      return 'Failed to create Private Endpoint'
    }
    if (privateLinkData?.phase === GetPrivateLinkEndpointRespPhase.Pending) {
      return 'Pending creation of Private Endpoint'
    }
    if (privateLinkData?.phase === GetPrivateLinkEndpointRespPhase.Available) {
      return 'Private Endpoint is available'
    }
    return 'Connect Preparation'
  }, [privateLinkData?.phase])

  return (
    <Modal
      opened={opened}
      size="xl"
      centered
      withCloseButton={false}
      onClose={onClose}
      title={
        <Text fw={700} fz={20}>
          {modalTitle}
        </Text>
      }
    >
      <Stack>
        <PrivateLinkMessage {...privateLinkData} serviceName={serviceName!} isAzureMysql={isAzureMysql} />
        <Group justify="flex-end">
          <Button variant="default" onClick={onClose} data-mp-event="mp-cancel-1691461017004">
            Cancel
          </Button>
          {privateLinkData?.phase === GetPrivateLinkEndpointRespPhase.PendingAcceptance ? (
            <Button onClick={onConfirmContinue} loading={loading} data-mp-event="mp-alreadydone,continue-1691461017006">
              Already done, continue
            </Button>
          ) : null}
        </Group>
      </Stack>
    </Modal>
  )
}

export default PrivateLinkCheck
