import { Box } from '@tidbcloud/uikit'
import { Alert, Button, Center, Divider, Group, Loader, Paper, Stack, Typography, notifier } from '@tidbcloud/uikit'
import { useEffect, useMemo } from 'react'
import { FormProvider, useForm, useWatch } from 'react-hook-form'
import { useQueryClient } from 'react-query'
import { useHistory } from 'react-router-dom'

import { markOneConsoleFeedbackEventCompleted } from 'dbaas/layouts/v5/NewNavGuide/feedbackState'
import { getListOrgProjectsQueryKey } from 'dbaas/services'
import {
  getTiDBServiceGetProjectMigrationTaskQueryKey,
  useTiDBServiceApproveProjectMigrationTask
} from 'dbaas/services/api-clients/v2023/cluster-management/v1beta2'
import { type V1beta2Migration } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta2/interface'
import useStores from 'dbaas/stores/useStores'
import { MixpanelEvents } from 'dbaas/utils/tracking/event'
import { projectNameRules } from 'dbaas/utils/validationRules'

import { trimProjectMigrationName } from '../shared/project-migration'

import { MigrationProjectCard } from './MigrationProjectCard'
import { MoveSettingsFormValues, type TargetProjectNameFieldName } from './move-settings.types'
import { validateProjectMigrationTargetName } from './project-name-validation'
import { useMoveSettingsData } from './use-move-settings-data'

interface MoveSettingsStepProps {
  migrations: V1beta2Migration[]
  onCancel: () => void
}

export const MoveSettingsStep = ({ migrations, onCancel }: MoveSettingsStepProps) => {
  const history = useHistory()
  const queryClient = useQueryClient()
  const {
    actions: { fetchUserProfileV2 },
    store: {
      userProfile: { id: userId },
      lastVisitLocation: { orgId }
    }
  } = useStores()
  const { cards, existingProjectNames, isError, isLoading } = useMoveSettingsData({
    migrations,
    enabled: true
  })

  const refreshProjectLists = async () => {
    return Promise.all([
      queryClient.invalidateQueries({
        queryKey: getTiDBServiceGetProjectMigrationTaskQueryKey({ orgId })
      }),
      queryClient.invalidateQueries({
        queryKey: getListOrgProjectsQueryKey(orgId),
        inactive: true
      }),
      fetchUserProfileV2()
    ])
  }

  const approveProjectMigrationTask = useTiDBServiceApproveProjectMigrationTask({
    mutation: {
      onSuccess: () => {
        refreshProjectLists()
        markOneConsoleFeedbackEventCompleted(userId, 'move')
        notifier.success('Migration completed.')
        history.push('/tidbs')
      },
      onError: () => {
        refreshProjectLists()
        notifier.info(
          'Migration has started. Please wait a while before making changes to the affected TiDB instances.'
        )
        history.push('/tidbs')
      }
    }
  })

  const form = useForm<MoveSettingsFormValues>({
    mode: 'onChange',
    defaultValues: {
      migrations: []
    }
  })
  const {
    control,
    getValues,
    handleSubmit,
    reset,
    trigger,
    formState: { isValid }
  } = form

  const fieldNames = useMemo(() => {
    return cards.map((_, index) => `migrations.${index}.targetProjectName` as const)
  }, [cards])
  const unavailableProjectNames = useMemo(() => {
    return [...existingProjectNames, ...cards.map((card) => card.sourceProjectName).filter(Boolean)]
  }, [cards, existingProjectNames])

  useEffect(() => {
    reset({
      migrations: cards.map((card) => ({
        sourceProjectId: card.sourceProjectId,
        targetProjectName: card.targetProjectName
      }))
    })
  }, [cards, reset])

  const watchedMigrations = useWatch({
    control,
    name: 'migrations'
  })

  useEffect(() => {
    if (!fieldNames.length) {
      return
    }

    trigger(fieldNames)
  }, [fieldNames, trigger, watchedMigrations])

  let content = (
    <Alert color="yellow" title="No projects to migrate" data-testid="project-migration-empty-state">
      This migration task does not include any projects.
    </Alert>
  )

  if (isLoading) {
    content = (
      <Center mih={240} data-testid="project-migration-move-settings-loading">
        <Loader />
      </Center>
    )
  } else if (isError) {
    content = (
      <Alert color="red" title="Failed to load migration details" data-testid="project-migration-move-settings-error">
        Refresh the page and try again.
      </Alert>
    )
  } else if (cards.length > 0) {
    content = (
      <Stack gap="md">
        {cards.map((card, index) => (
          <MigrationProjectCard
            key={card.sourceProjectId}
            card={card}
            fieldName={`migrations.${index}.targetProjectName` as TargetProjectNameFieldName}
            rules={{
              ...projectNameRules,
              validate: (value: string) =>
                validateProjectMigrationTargetName({
                  value,
                  currentIndex: index,
                  migrations: getValues('migrations') || [],
                  existingProjectNames: unavailableProjectNames
                })
            }}
          />
        ))}
      </Stack>
    )
  }

  return (
    <FormProvider {...form}>
      <Paper withBorder data-testid="project-migration-move-settings-step">
        <Box
          component="form"
          onSubmit={handleSubmit((values) => {
            return approveProjectMigrationTask.mutateAsync({
              data: {
                migrations: values.migrations.map((migration) => ({
                  sourceProjectId: migration.sourceProjectId,
                  targetProjectName: trimProjectMigrationName(migration.targetProjectName)
                }))
              },
              params: {
                orgId
              }
            })
          })}
        >
          <Stack gap="xl" p="xl">
            <Typography variant="headline-sm">Review and name the new projects</Typography>
            {content}
          </Stack>

          <Divider />
          <Group justify="flex-end" px="xl" py="md">
            <Button
              variant="default"
              onClick={onCancel}
              disabled={approveProjectMigrationTask.isLoading}
              data-testid="project-migration-do-it-later-button"
              data-mp-event={MixpanelEvents.ProjectMigration.View.CancelClicked}
            >
              Do it later
            </Button>
            <Button
              type="submit"
              disabled={isLoading || isError || !cards.length || !isValid}
              loading={approveProjectMigrationTask.isLoading}
              data-testid="project-migration-confirm-button"
              data-mp-event={MixpanelEvents.ProjectMigration.Move.SubmitClicked}
            >
              Confirm and move
            </Button>
          </Group>
        </Box>
      </Paper>
    </FormProvider>
  )
}
