import { notifier, Alert, Button, ButtonProps, Flex, Modal } from '@tidbcloud/uikit'
import { Form, FormTextInput } from '@tidbcloud/uikit/biz'
import { usePrevious } from '@tidbcloud/uikit/hooks'
import { useEffect, useState } from 'react'

import { useHelpCenterContext } from 'dbaas/screens/HelpCenter/context'
import { GUIDED_TOUR_OF_ENDPOINTS_PATH } from 'dbaas/screens/HelpCenter/DataService'
import { onlineDataApiEndpoint, getEndpointVersions, useGetEndpointDeployStatus } from 'dbaas/services/dataservice'
import { eventTracking } from 'dbaas/utils/tracking'

import DiscardButton from '../common/DiscardButton'
import { useDataApiContext } from '../context'
import Diff from '../DataAppDetail/Deployment/Diff'
import {
  useTestEndpoint,
  useChangeEndpointStatus,
  useEndpointPathValid,
  useClusterValid,
  showErrorMsg,
  hasEndpointMointerKeyChanged
} from '../helpers'
import { VersionItem, EndPoint } from '../types'

interface DefaultProps extends ButtonProps {
  endpoint: EndPoint
  source?: string
  text?: string
  showMsg?: boolean
  isCompact?: boolean
  onError?: () => void
  onSuccess?: () => void
}

const Deploy: React.FC<React.PropsWithChildren<DefaultProps>> = ({
  endpoint,
  source = '',
  text,
  showMsg,
  onError,
  onSuccess,
  isCompact,
  ...rest
}) => {
  const {
    orgId,
    projectId,
    editEndpoint,
    editEndpointRef,
    setEditEndpoint,
    versions,
    setVersions,
    sqlText,
    sqlTextRef,
    setIsAutoSaveClose,
    dataappDeployConfig,
    appDeploying,
    setEndpointDeployMsg
  } = useDataApiContext()
  const { dataServiceGuideStep, setDataServiceGuideStep, openDialog, setCurrentPath } = useHelpCenterContext()

  const { saveEndpoint } = useTestEndpoint()
  const { update: updateEndpointStatus } = useChangeEndpointStatus()
  const [opened, setOpened] = useState(false)
  const { validPath } = useEndpointPathValid()
  const { validCluster } = useClusterValid()
  const [saveed, setSaveed] = useState(false)
  const prevEditEndpoint = usePrevious(editEndpoint)

  useGetEndpointDeployStatus(
    orgId,
    projectId,
    `${endpoint?.dataappp_id}`,
    `${endpoint?.id}`,
    (versions.length && versions[0].version) || '',
    {
      query: {
        enabled:
          !!orgId &&
          !!projectId &&
          !!endpoint?.id &&
          !!versions.length &&
          !!versions[0].version &&
          !!editEndpoint?.deploying,
        refetchInterval: 10 * 1000,
        refetchIntervalInBackground: true,
        refetchOnWindowFocus: false,
        onSuccess: (res) => {
          if (res.data?.completed === true) {
            updateEndpointDeploy({ deploying: false })
          }
        }
      }
    }
  )

  useEffect(() => {
    if (!editEndpoint || prevEditEndpoint?.sql_template === undefined) {
      return
    }

    if (prevEditEndpoint && editEndpoint.id !== prevEditEndpoint.id) {
      return
    }

    if (!editEndpointRef.current) {
      return
    }

    const hasChanged = hasEndpointMointerKeyChanged(prevEditEndpoint, editEndpointRef.current, sqlTextRef.current)
    if (hasChanged && !editEndpointRef.current.has_modified) {
      const data = {
        ...editEndpointRef.current,
        sql_template: sqlTextRef.current,
        has_modified: true
      }
      setEditEndpoint(data)
      editEndpointRef.current = data
    }
  }, [editEndpoint])

  useEffect(() => {
    if (!editEndpointRef.current || !editEndpoint || prevEditEndpoint?.sql_template === undefined) {
      return
    }

    if (prevEditEndpoint && editEndpoint.id !== prevEditEndpoint.id) {
      return
    }

    if (editEndpointRef.current.sql_template === sqlText) {
      return
    }

    if (editEndpoint.type === 'system-data') {
      return
    }

    const endpoint = {
      ...editEndpointRef.current,
      has_modified: true
    }
    setEditEndpoint(endpoint)
    editEndpointRef.current = endpoint
  }, [sqlText])

  const deployHandler = async (values: { deploy_name: string }) => {
    updateEndpointDeploy({ deploying: true })
    try {
      const res = await onlineDataApiEndpoint(orgId, projectId, `${endpoint?.dataappp_id}`, `${endpoint?.id}`, {
        deploy_name: values.deploy_name || 'Deploy from Data App'
      })
      setEndpointDeployMsg(res.code === 200 ? '' : res.message || `The endpoint ${endpoint?.name} deployed failed`)
      if (res.code === 200) {
        if (dataServiceGuideStep === 9) {
          notifier.success('Your endpoint is deployed successfully.', {
            title: 'Congratulations!'
          })
        } else {
          notifier.success(`The endpoint ${endpoint?.name} has been deployed successfully`)
        }

        updateEndpointStatus(`${endpoint?.dataappp_id}`, `${endpoint?.id}`, 1)
        updateEndpointDeploy({ has_modified: false })
        setOpened(false)
        onSuccess?.()
        if (dataServiceGuideStep > 1) {
          openDialog()
          setCurrentPath(GUIDED_TOUR_OF_ENDPOINTS_PATH)
          setDataServiceGuideStep(0)
          eventTracking('Guided Tour step 9')
        }
      } else {
        throw new Error(res.message)
      }
    } catch (e) {
      updateEndpointDeploy({ deploying: false })
      updateEndpointDeploy({ has_modified: true })
      const msg = showErrorMsg(e, showMsg || false)
      setEndpointDeployMsg(msg)
      setOpened(false)
      onError?.()
    }

    const verRes = await getEndpointVersions(
      orgId,
      projectId,
      `${endpoint?.dataappp_id || ''}`,
      `${endpoint?.id || ''}`
    )

    if (verRes.code === 200) {
      setVersions(verRes.data as VersionItem[])
    }
  }

  const updateEndpointDeploy = (params: Pick<EndPoint, any>) => {
    const data = {
      ...editEndpointRef.current,
      ...params
    } as EndPoint
    setEditEndpoint(data)
    editEndpointRef.current = data
  }

  useEffect(() => {
    setIsAutoSaveClose(opened)
    saveWhenOpen(opened)

    if (!opened) {
      setSaveed(false)
    }
  }, [opened])

  const saveWhenOpen = async (opened: boolean) => {
    if (opened) {
      try {
        await saveEndpoint()
      } catch (_e) {
      } finally {
        setSaveed(true)
      }
    }
  }

  return (
    <>
      <Button
        data-guide="deploy"
        size={`${isCompact ? 'compact-' : ''}xs`}
        variant="default"
        data-testid="deploy-endpoint"
        data-mp-event="DataService deploy endpoint clicked"
        data-mp-source={source}
        disabled={!editEndpoint?.has_modified}
        loading={editEndpoint?.deploying || appDeploying}
        {...rest}
        onClick={async () => {
          const pathRes = validPath()
          const clusterRes = validCluster()
          if (!pathRes || !clusterRes) {
            onError?.()
            return
          }

          if (!dataappDeployConfig?.enable_ui_drafts) {
            updateEndpointDeploy({ deploying: true })
            try {
              await saveEndpoint()
            } catch (_e) {
              updateEndpointDeploy({ deploying: false })
            }

            deployHandler({ deploy_name: '' })
            return
          }

          setOpened(true)
          setTimeout(() => {
            if (dataServiceGuideStep > 1) {
              setDataServiceGuideStep(dataServiceGuideStep + 1)
              eventTracking('Guided Tour step 8')
            }
          }, 2000)
        }}
      >
        {text || 'Deploy'}
      </Button>

      <Modal
        data-guide="deploy-modal"
        title="Are you sure to deploy the endpoint?"
        centered
        size="80%"
        opened={opened}
        closeOnClickOutside={false}
        withCloseButton={dataServiceGuideStep !== 9}
        onClose={() => setOpened(false)}
        zIndex={9999}
      >
        <Form
          layout="none"
          actionsProps={{
            confirmText: `Re-deploy ${dataappDeployConfig?.enable_automatic_deployment ? 'and Push to GitHub' : ''}`
          }}
          withActions={false}
          onSubmit={deployHandler}
        >
          <FormTextInput
            name="deploy_name"
            readOnly={dataServiceGuideStep === 9}
            defaultValue={dataServiceGuideStep === 9 ? 'Initial deployment of companyInfo endpoint' : undefined}
            label="Change Description"
            placeholder="Deploy from Data App"
            mb={16}
          />

          {saveed && <Diff maxHeight={'40vh'} endpointId={`${editEndpoint?.id}`} />}

          <Alert c="blue" mt={16}>
            If choosing "Discard Draft" will roll back to the last deployment content.
            {dataappDeployConfig?.enable_automatic_deployment &&
              ` If choosing "Deploy and Push to GitHub" will push the changes to your GitHub Repo and override.`}
          </Alert>

          <Flex justify="flex-end" gap={24} mt={24}>
            <DiscardButton
              buttonProps={{ disabled: dataServiceGuideStep === 9 }}
              data-mp-event="Dataservice discard endpoint draft button clicked"
              data-mp-source="top-menu"
              type="endpoint"
              succCallback={() => {
                setOpened(false)
              }}
            />
            <Button
              type="submit"
              loading={editEndpoint?.deploying}
              disabled={!saveed}
              data-testid="deploy-endpoint-confirm"
              data-mp-event="Dataservice deploy endpoint button clicked"
            >
              Deploy {dataappDeployConfig?.enable_automatic_deployment ? 'and Push to GitHub' : ''}
            </Button>
          </Flex>
        </Form>
      </Modal>
    </>
  )
}

export default Deploy
