import { Alert, Flex, Tooltip, ActionIcon, Button, HoverCard } from '@tidbcloud/uikit'
import { FormTextInput, FormSelect } from '@tidbcloud/uikit/biz'
import { createStyles } from '@tidbcloud/uikit/emotion'
import { IconInfoCircle, IconRefreshCw02, IconAlertCircle } from '@tidbcloud/uikit/icons'
import { useEffect, useMemo } from 'react'
import { useFormContext } from 'react-hook-form'

import {
  useGetPreflightRepos,
  useGetPreGithubBranches,
  useValidatePreRepos,
  useGetDataappAuthorizedRepos,
  useGetAuthorizedGithubBranches,
  useValidateRepos
} from 'dbaas/services/dataservice'

import GithubDocument from '../common/GithubDocument'
import { useDataApiContext } from '../context'
import { useGithubAuthRequest } from '../helpers'

const useStyles = createStyles((_theme, { inputHeight }: { inputHeight: number }) => ({
  root: {
    flex: 1,
    input: {
      height: inputHeight,
      minHeight: inputHeight
    }
  }
}))

const Repos = ({
  authed,
  isCreate,
  hasRefreshBtn = true,
  inputHeight = 40,
  children,
  defaultValue,
  disabled = false
}: {
  authed: boolean
  isCreate: boolean
  hasRefreshBtn?: boolean
  inputHeight?: number
  children?: React.ReactNode
  defaultValue?: {
    directory: string
    repository_id: string
    branch: string
  }
  disabled?: boolean
}) => {
  const { orgId, projectId, editApp, isReposConflict, setIsReposConflict, directoryErrInfo, setDirectoryErrInfo } =
    useDataApiContext()
  const [requestId] = useGithubAuthRequest()
  const { watch, setValue } = useFormContext()
  const repository = watch('repository_id')
  const branch = watch('branch')
  const directory = watch('directory')
  const validMutation = useValidatePreRepos()
  const configValidMutation = useValidateRepos()
  const { classes } = useStyles({ inputHeight })

  useEffect(() => {
    setValue('repository_id', defaultValue?.repository_id ?? '')
    setValue('directory', defaultValue?.directory ?? '')
    setValue('branch', defaultValue?.branch ?? '')
  }, [])

  const {
    data: repos,
    isLoading: reposLoading,
    isRefetching: reposRefetching,
    refetch: refetchRepos
  } = useGetPreflightRepos(orgId, projectId, requestId, {
    query: {
      enabled: !!orgId && !!projectId && !!requestId && !!isCreate && !!authed,
      refetchInterval: false,
      refetchOnWindowFocus: false
    }
  })

  const { data: authorizedRepos, refetch: refetchAuthorizedRepos } = useGetDataappAuthorizedRepos(
    orgId,
    projectId,
    `${editApp?.id}`,
    {
      query: {
        enabled: !!orgId && !!projectId && !isCreate && !!editApp && !!authed,
        refetchInterval: false,
        refetchOnWindowFocus: false
      }
    }
  )

  useEffect(() => {
    setIsReposConflict(false)
    if (repository && branch && directory) {
      check()
    }
  }, [repository, branch, directory])

  const check = async () => {
    let res
    if (!isCreate) {
      res = await configCheck()
    } else {
      res = await preCheck()
    }

    setIsReposConflict(!!res.data?.external_app_id)
  }

  const preCheck = async () => {
    const res = await validMutation.mutateAsync({
      orgId,
      projectId,
      requestId,
      repoId: repository.split('-')[0],
      data: {
        branch,
        directory
      }
    })
    return res
  }

  const configCheck = async () => {
    const res = await configValidMutation.mutateAsync({
      orgId,
      projectId,
      appId: `${editApp?.id}`,
      repoId: repository.split('-')[0],
      data: {
        branch,
        directory
      }
    })
    return res
  }

  const isRepoEnable = useMemo(() => {
    if (!repository) {
      return false
    }

    const repositorys = repository.split('-')
    if (repositorys.length !== 2) {
      return false
    }
    return repositorys[0] !== '0' && repositorys[1] !== '0'
  }, [repository])

  const { data: branches, refetch: refetchBranches } = useGetPreGithubBranches(
    orgId,
    projectId,
    requestId,
    (repository && repository.split('-')[0]) || '',
    {
      query: {
        enabled: !!orgId && !!projectId && !!requestId && isRepoEnable && isCreate,
        refetchInterval: false,
        refetchOnWindowFocus: false,
        refetchIntervalInBackground: false
      }
    }
  )

  const { data: authorizedBranches, refetch: refetchAuthorizedBranches } = useGetAuthorizedGithubBranches(
    orgId,
    projectId,
    `${editApp?.id}`,
    repository && repository.split('-')[0],
    {
      query: {
        enabled: !!orgId && !!projectId && !isCreate && isRepoEnable && !isCreate,
        refetchInterval: false,
        refetchOnWindowFocus: false,
        onSuccess: (res) => {
          if (res.data) {
            const cur = res.data.find((item) => item.name === branch)
            if (!cur || cur.protected) {
              setValue('branch', '')
            }
          }
        }
      }
    }
  )

  const refresh = () => {
    isCreate ? refetchRepos() : refetchAuthorizedRepos()
    const isRepositoryValid = repository && !repository.split('-').includes('0')
    if (isRepositoryValid) {
      isCreate ? refetchBranches() : refetchAuthorizedBranches()
    }
  }

  const repoList = !isCreate ? authorizedRepos?.data : repos?.data
  const branchList = !isCreate ? authorizedBranches?.data : branches?.data

  return (
    <>
      <Flex gap={8} mt={16} align="end">
        <FormSelect
          label={
            <Flex align="center">
              Repository
              <HoverCard width={420} position="top" withArrow shadow="md" zIndex={9999}>
                <HoverCard.Target>
                  <ActionIcon aria-label="Info" size={20} ml={4}>
                    <IconInfoCircle size={16} />
                  </ActionIcon>
                </HoverCard.Target>
                <HoverCard.Dropdown>
                  The repository will include linked data sources and endpointrelated information. It's important to
                  note that sensitive information like API keys will not be included.If you think the data saved is
                  sensitive, consider using a private repository.
                </HoverCard.Dropdown>
              </HoverCard>
            </Flex>
          }
          name="repository_id"
          placeholder="Select repository"
          disabled={!authed || disabled}
          data={(repoList || []).map((repo) => ({
            label: repo.full_name ?? '',
            value: `${repo.id}-${repo.installation_id}`
          }))}
          className={classes.root}
          searchable
          nothingFoundMessage="No repository found"
        />

        <FormSelect
          label="Branch"
          name="branch"
          placeholder="Select branch"
          disabled={!repository || disabled}
          defaultValue={defaultValue?.branch}
          data={(branchList || []).map((branch) => ({
            label: branch.name ?? '',
            value: branch.name ?? '',
            disabled: branch.protected
          }))}
          className={classes.root}
          searchable
          nothingFoundMessage="No branch found"
        />

        <FormTextInput
          label={
            <Flex align="center">
              Directory
              <HoverCard width={420} position="top" withArrow shadow="md" zIndex={9999}>
                <HoverCard.Target>
                  <ActionIcon aria-label="Info" size={20} ml={4}>
                    <IconInfoCircle size={16} />
                  </ActionIcon>
                </HoverCard.Target>
                <HoverCard.Dropdown>
                  If the directory you specified does not exist in the GitHub repository, it will be created
                  automatically.{' '}
                </HoverCard.Dropdown>
              </HoverCard>
            </Flex>
          }
          error={!!isReposConflict || !!directoryErrInfo}
          name="directory"
          defaultValue={defaultValue?.directory}
          placeholder="Input directory"
          disabled={!branch || disabled}
          className={classes.root}
          maxLength={255}
          onChange={(e) => {
            const val = e.target.value
            if (!val) {
              setDirectoryErrInfo('Please enter directory.')
            } else if (!/^\/$|\/(?:[\w-]+\/)*(?:[\w-]+|\d)$/g.test(val)) {
              setDirectoryErrInfo(
                'The directory must start with /, followed by a sequence of one or more directory names. Each directory name must only contain letters, numbers, hyphens(-), underscores(_). Trailing slash are not allowed.'
              )
            } else {
              setDirectoryErrInfo('')
            }
          }}
        />

        {hasRefreshBtn && (
          <Tooltip
            multiline
            w={255}
            withArrow
            disabled={reposLoading || reposRefetching}
            label="Click the refresh button to update the list of GitHub repositories and branches and see any newly added ones"
          >
            <Button
              variant="default"
              size="compact-lg"
              disabled={!authed}
              loading={reposLoading || reposRefetching}
              onClick={refresh}
              data-mp-event="mp--1691461014974"
            >
              <IconRefreshCw02 size={20} />
            </Button>
          </Tooltip>
        )}

        {children}
      </Flex>

      {(isReposConflict || directoryErrInfo) && (
        <Alert
          color="red"
          m={'8px 0 8px'}
          icon={<IconAlertCircle />}
          styles={() => ({
            root: {
              whiteSpace: 'break-spaces'
            }
          })}
        >
          {isReposConflict ? (
            <>
              The directory '{directory}' is already associated with a different Data App. Please choose a different
              directory to proceed with the configuration. If you import an existing data application in github repo,
              please follow the instructions [
              <GithubDocument text="here" />
              ].
            </>
          ) : (
            <>{directoryErrInfo}</>
          )}
        </Alert>
      )}
    </>
  )
}

export default Repos
