import { Divider, Group, Loader, Stack, notifier } from '@tidbcloud/uikit'
import { FormPasswordInput, FormSelect, FormTextInput } from '@tidbcloud/uikit/biz'
import { useMemo, useRef } from 'react'
import { Controller, useFormContext } from 'react-hook-form'

import { useIsEditingChangefeed } from 'dbaas/features/Changefeed'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { useGetPrivateLinkService } from 'dbaas/services'
import { useTiDBServiceListTidbs } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta2'
import { TiDBServiceListTidbsServicePlansItem } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta2/interface'
import { useCreateSinkEndpoint, useGetSinkEndpoint, useListSinkEndpoints } from 'dbaas/services/dataflow'

import { buildActiveServerlessClusterOptions } from './serverlessClusterOptions'

export const useServerlessSinkEndpointFlow = ({
  orgId,
  projectId,
  targetClusterId,
  targetProjectId,
  serverlessProvider,
  serverlessRegion,
  sinkEndpointId,
  enabled,
  onAvailable,
  setValue
}: {
  orgId: string
  projectId: string
  targetClusterId: string
  targetProjectId: string
  serverlessProvider: string
  serverlessRegion: string
  sinkEndpointId: string
  enabled?: boolean
  onAvailable: () => void
  setValue: (name: string, value: string) => void
}) => {
  const hasTriggeredNextRef = useRef(false)
  const shouldAutoNextRef = useRef(false)
  const plServiceQuery = useGetPrivateLinkService(orgId, targetProjectId, targetClusterId, {
    query: {
      enabled: enabled !== false && Boolean(targetClusterId) && Boolean(targetProjectId),
      refetchOnWindowFocus: false
    }
  })
  const plServiceData = plServiceQuery.data
  const serverlessPrivateLinkMetaError = plServiceQuery.error
  const isLoadingServerlessPrivateLinkMeta = plServiceQuery.isLoading

  const createSinkEndpointForServerless = useCreateSinkEndpoint()
  const { data: listSinkEndpointsData, refetch: refetchListSinkEndpoints } = useListSinkEndpoints(
    orgId,
    projectId,
    {
      provider: serverlessProvider,
      region: serverlessRegion
    },
    {
      query: {
        enabled:
          Boolean(orgId) &&
          Boolean(projectId) &&
          Boolean(serverlessProvider) &&
          Boolean(serverlessRegion) &&
          enabled !== false,
        refetchOnMount: false,
        refetchOnWindowFocus: false
      }
    }
  )
  const { data: serverlessSinkEndpointData, error: getServerlessSinkEndpointError } = useGetSinkEndpoint(
    orgId,
    projectId,
    sinkEndpointId,
    {
      query: {
        enabled: Boolean(sinkEndpointId) && enabled !== false,
        refetchOnWindowFocus: false,
        refetchInterval(data) {
          if (data?.status === 'SINK_ENDPOINT_STATUS_AVAILABLE' || data?.status === 'SINK_ENDPOINT_STATUS_FAILED') {
            return false
          }
          return 3000
        },
        onSuccess(data) {
          if (
            data.status === 'SINK_ENDPOINT_STATUS_AVAILABLE' &&
            shouldAutoNextRef.current &&
            !hasTriggeredNextRef.current
          ) {
            hasTriggeredNextRef.current = true
            shouldAutoNextRef.current = false
            onAvailable()
          }
        }
      }
    }
  )

  const createServerlessSinkEndpoint = async () => {
    hasTriggeredNextRef.current = false
    shouldAutoNextRef.current = false

    if (!targetClusterId) {
      notifier.error('Please select a Starter instance in the same region.')
      return
    }

    if (sinkEndpointId && serverlessSinkEndpointData?.status === 'SINK_ENDPOINT_STATUS_AVAILABLE') {
      hasTriggeredNextRef.current = true
      onAvailable()
      return
    }

    const serviceName = plServiceData?.privatelink_service?.name || ''
    shouldAutoNextRef.current = true
    const reusableEndpoint = listSinkEndpointsData?.sink_endpoints?.find(
      (endpoint) => endpoint.endpoint_service_name === serviceName && endpoint.properties?.internal === 'true'
    )
    if (reusableEndpoint?.id) {
      setValue('tidb.mysql_info.privatelink_info.df_privatelink_endpoint_id', reusableEndpoint.id)
      return
    }

    const { id } = await createSinkEndpointForServerless.mutateAsync({
      orgId,
      projectId,
      data: {
        endpoint_name: `cdc-tidb`,
        endpoint_service_name: serviceName,
        provider: serverlessProvider,
        region: serverlessRegion,
        service_region: serverlessRegion,
        properties: {
          internal: 'true'
        }
      }
    })

    // Refresh the sink endpoint list after creating a new one
    refetchListSinkEndpoints()

    if (id) {
      setValue('tidb.mysql_info.privatelink_info.df_privatelink_endpoint_id', id)
    }
  }

  return {
    createServerlessSinkEndpoint,
    error: serverlessPrivateLinkMetaError || createSinkEndpointForServerless.error || getServerlessSinkEndpointError,
    isCreatingServerlessSinkEndpoint: createSinkEndpointForServerless.isLoading,
    isLoading: isLoadingServerlessPrivateLinkMeta || createSinkEndpointForServerless.isLoading,
    serverlessSinkEndpointData
  }
}

export function FormTiDBServerless({ orgId, cluster }: { orgId: string; cluster: SharedCluster }) {
  const isEditing = useIsEditingChangefeed()
  const { control } = useFormContext()
  const { data: clustersData, isLoading: isLoadingClusterOptions } = useTiDBServiceListTidbs(
    {
      orgId,
      skip: 0,
      pageSize: 100,
      servicePlans: [TiDBServiceListTidbsServicePlansItem.Starter, TiDBServiceListTidbsServicePlansItem.Essential],
      regionIds: [cluster.regionId]
    },
    {
      query: {
        refetchOnWindowFocus: false
      }
    }
  )

  const serverlessClusterOptions = useMemo(
    () => buildActiveServerlessClusterOptions(clustersData?.tidbs),
    [clustersData]
  )

  return (
    <>
      <Divider />
      <Stack m={24} maw={1000}>
        <Controller
          name="tidb.mysql_info.privatelink_info.df_privatelink_endpoint_id"
          control={control}
          render={({ field }) => <input {...field} hidden />}
        />

        <FormSelect
          label="Cluster"
          name="tidb.cluster_id"
          rules={{ required: 'Required' }}
          data={serverlessClusterOptions}
          disabled={isEditing}
          rightSection={isLoadingClusterOptions ? <Loader size="xs" /> : undefined}
          placeholder="Select a cluster"
          inputWrapperOrder={['label', 'input', 'description', 'error']}
          description={`Only active clusters in the same region (${cluster.regionId}) are available here.`}
        />

        <Group>
          <FormTextInput
            name="tidb.mysql_info.connection.username"
            label="User Name"
            rules={{ required: 'Required' }}
            placeholder="Enter the user name"
            sx={() => ({ flex: 1 })}
          />

          <FormPasswordInput
            name="tidb.mysql_info.connection.password"
            label="Password"
            placeholder="Enter the password"
            sx={() => ({ flex: 1 })}
          />
        </Group>
      </Stack>
    </>
  )
}
