import { Alert, AlertProps, Box, Loader, Typography } from '@tidbcloud/uikit'
import { IconCheckCircleBroken, IconXCircle } from '@tidbcloud/uikit/icons'
import DOMPurify from 'dompurify'
import { forwardRef, useEffect, useImperativeHandle } from 'react'
import { Link } from 'react-router-dom'

import { useIsImportReady } from 'dbaas/screens/GettingStarted/helpers'
import {
  useImportServiceCreateImport,
  useImportServiceValidateImport
} from 'dbaas/services/api-clients/legacy/serverless'
import {
  ConsoleImportServiceCreateImportBody,
  ImportS3AuthTypeEnum,
  ImportSourceTypeEnum,
  ImportValidationTypeEnum
} from 'dbaas/services/api-clients/legacy/serverless/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'

export interface LoadDatasetProps {
  clusterId: string
  orgId: string
  projectId: string
  importId?: string
  region?: string
  database: string
  tables?: string[]
  s3: string
  arn: string
  loaded?: boolean
  onLoadStart?: (id: string) => void
  onLoadTerminated?: () => void
  onLoaded?: () => void
  validateData?: boolean
}

export const ImportSampleData = forwardRef<{ import: () => Promise<void> }, LoadDatasetProps>(
  (
    {
      clusterId,
      s3,
      arn,
      onLoaded,
      loaded,
      database,
      onLoadStart,
      importId,
      onLoadTerminated,
      tables = [],
      orgId,
      projectId,
      validateData = false
    },
    ref
  ) => {
    const validateImport = useImportServiceValidateImport({
      request: {
        timeout: 60 * 1000
      }
    })
    const createImport = useImportServiceCreateImport({ request: { timeout: 10 * 60 * 1000 } })
    const {
      ready: importReady,
      error: importError,
      remove: removeImportStatus,
      canceled: importCanceled,
      terminated: importTerminated
    } = useIsImportReady(clusterId, loaded ? '' : importId || createImport.data?.id || '')

    const importHandler = async (truncateTables?: boolean) => {
      const payload: ConsoleImportServiceCreateImportBody = {
        source: {
          type: ImportSourceTypeEnum.S3,
          s3: {
            uri: s3,
            auth_type: ImportS3AuthTypeEnum.ROLE_ARN,
            role_arn: arn,
            target_table_infos: truncateTables
              ? tables.map((table) => ({ target_table: { table, database } }))
              : undefined
          }
        },
        import_options: {
          file_type: 'SQL',
          need_drop_table: truncateTables
        }
      }

      const data = await createImport.mutateAsync({
        orgId,
        projectId: projectId,
        clusterId,
        data: payload
      })
      onLoadStart?.(data.id || '')
    }

    const validate = async (truncateTables?: boolean) => {
      try {
        // reset status
        onLoadStart?.('')
        createImport.reset()
        validateImport.reset()
        removeImportStatus()
        // skip validate data can save at least 5 seconds
        if (validateData) {
          await validateImport.mutateAsync({
            orgId,
            projectId: projectId,
            clusterId,
            data: {
              validation_type: ImportValidationTypeEnum.SOURCE_ACCESS_CHECK,
              source: {
                type: ImportSourceTypeEnum.S3,
                s3: {
                  uri: s3,
                  auth_type: ImportS3AuthTypeEnum.ROLE_ARN,
                  role_arn: arn
                }
              }
            }
          })
        }

        await importHandler(truncateTables)
      } catch (_e) {
        onLoadTerminated?.()
      }
    }

    useEffect(() => {
      createImport.reset()
      validateImport.reset()
      removeImportStatus()
    }, [clusterId])

    const error =
      getErrorMessage(validateImport.error || createImport.error) ||
      importError ||
      (importCanceled ? 'The import task is canceled.' : '')
    const isImporting =
      validateImport.isLoading ||
      createImport.isLoading ||
      ((!!createImport.data?.id || !!importId) && !importReady && !error && !loaded && !importTerminated)
    const isImported = ((createImport.isSuccess || importId) && importReady) || loaded

    useEffect(() => {
      if (isImported) {
        onLoaded?.()
      }
    }, [isImported])

    useEffect(() => {
      if (importTerminated || error) {
        onLoadTerminated?.()
      }
    }, [importTerminated, error])

    useEffect(() => {
      if (isImporting && importId) {
        onLoadStart?.(importId)
      }
    }, [isImporting, importId])

    const alertStyles: AlertProps['styles'] = (theme) => ({
      root: {
        border: 'none',
        borderRadius: theme.defaultRadius,
        marginTop: 48
      },
      icon: {
        alignSelf: 'center',
        marginRight: '16px !important'
      }
    })

    useImperativeHandle(ref, () => {
      return {
        import: () => {
          if (isImported) {
            return Promise.reject()
          }
          return validate()
        }
      }
    }, [])

    return (
      <Box pb={24} w="100%">
        {isImporting && (
          <Alert styles={alertStyles} c="carbon.8" icon={<Loader size={22} color="carbon.7" />}>
            Importing sample data.. You can always check the import status in{' '}
            <Link to={`/clusters/${clusterId}/imports`}>Import</Link> page.
          </Alert>
        )}
        {isImported && (
          <Alert styles={alertStyles} c="green" icon={<IconCheckCircleBroken size={24} />}>
            <Typography variant="body-lg" c="carbon.9">
              Your sample data is ready.
            </Typography>
          </Alert>
        )}
        {!!error && (
          <Alert icon={<IconXCircle size={24} />} color={'red'} styles={alertStyles}>
            Your data import is failed (Reason:{' '}
            <span dangerouslySetInnerHTML={{ __html: DOMPurify.sanitize(error) }}></span>). Try{' '}
            <a onClick={() => validate()}>import sample data again</a> or{' '}
            <Link to={`/clusters/${clusterId}/imports`}>import your own data</Link>. You can always check your import
            tasks in the Import page.
          </Alert>
        )}
      </Box>
    )
  }
)
