import {
  ActionIcon,
  Alert,
  Box,
  Button,
  Card,
  Flex,
  Group,
  Modal,
  Typography,
  Loader,
  Kbd,
  openConfirmModal,
  notifier
} from '@tidbcloud/uikit'
import { Form } from '@tidbcloud/uikit/biz'
import { IconDataService, IconEdit05, IconGithub, IconXClose } from '@tidbcloud/uikit/icons'
import { useEffect, useMemo, useState } from 'react'
import { useForm } from 'react-hook-form'

import { useIsGithubLinked, useLinkedGithubDataapp, useUnlinkedGithubDataapp } from 'dbaas/services/dataservice'
import { DtoGithubLinkageStatusResult } from 'dbaas/services/dataservice/interface'

import GithubAuth from '../../common/GithubAuth'
import GithubDocument from '../../common/GithubDocument'
import { useDataApiContext } from '../../context'
import Repos from '../../CreateApp/Repos'
import { clearCreateFormStorageDatas } from '../../helpers'

interface FormValues {
  branch: string
  directory: string
  repository_id: string
  enable_automatic_deployment?: boolean
}

const LinkedRepo = ({ linkInfo }: { linkInfo: DtoGithubLinkageStatusResult }) => {
  const propertiesConfig = [
    {
      name: 'Repository',
      value: linkInfo.repository_full_name
    },
    {
      name: 'Branch',
      value: linkInfo.branch
    },
    {
      name: 'Directory',
      value: linkInfo.directory
    }
  ]
  return (
    <Box mt={20}>
      {propertiesConfig.map((v, i) => (
        <Group align="center" mb={22} key={i}>
          <Typography variant="label-md" w={150}>
            {v.name}
          </Typography>
          <Typography
            variant="body-sm"
            sx={() => ({ overflow: 'hidden', textOverflow: 'ellipsis', width: 0, flex: 1 })}
          >
            {v.value}
          </Typography>
        </Group>
      ))}
    </Box>
  )
}

const UnlinkedRepo = ({ linked }: { linked: boolean }) => {
  return (
    <Flex direction="column" justify="center" sx={{ flex: 1 }} gap={28}>
      <Flex align="center" gap={18}>
        <Box component={IconDataService} c="carbon.6" w={40} h={40}></Box>
        <Box component={IconXClose} c="carbon.6" w={24} h={24}></Box>
        <Box component={IconGithub} c="carbon.6" w={40} h={40}></Box>
      </Flex>
      <Typography variant="body-md" sx={{ whiteSpace: 'break-spaces' }}>
        {linked ? (
          <>
            You haven't selected a repository, branch, and directory yet. Please click{' '}
            <Kbd>
              <IconEdit05 size={12} />
            </Kbd>{' '}
            to provide the necessary information.
          </>
        ) : (
          <>
            To seamlessly integrate TiDB Cloud Data Service with your system architecture and DevOps process, you can
            manage all configurations of your data application as code files through GitHub repositories. If you
            associate GitHub for deployment purposes, please follow the instructions provided{' '}
            <GithubDocument text="here" ml={4} />.
          </>
        )}
      </Typography>
    </Flex>
  )
}

const GitHub = ({ onChange }: { onChange?: (linked: boolean) => void }) => {
  const {
    orgId,
    projectId,
    editApp,
    updateDeployConfig,
    directoryErrInfo,
    setDirectoryErrInfo,
    isReposConflict,
    setIsReposConflict,
    dataappDeployConfig
  } = useDataApiContext()
  const [opened, setOpened] = useState(false)
  const [editOpen, setEditOpen] = useState(false)
  const link = useLinkedGithubDataapp()
  const unlink = useUnlinkedGithubDataapp()
  const formProps = useForm<FormValues>({})
  const { watch } = formProps
  const directory = watch('directory')
  const branch = watch('branch')

  // useEffect needs appropriate dependencies, otherwise it will cause continuous re-renders
  useEffect(() => {
    if (JSON.parse(localStorage.getItem('github_connecting') || '{}') === 'true') {
      setOpened(true)
    }
  }, [])

  const {
    data: linkInfo,
    isFetching,
    refetch
  } = useIsGithubLinked(orgId, projectId, `${editApp?.id}`, {
    query: {
      enabled: !!orgId && !!projectId && !!editApp?.id,
      refetchInterval: false,
      refetchOnWindowFocus: false,
      onSuccess: (data) => {
        onChange && onChange(data?.data?.authorized || false)
      }
    }
  })

  const linked = linkInfo?.data?.authorized

  const openUnlinkModal = () => {
    openConfirmModal({
      title: 'Disconnect Authorized GitHub Accounts',
      centered: true,
      size: 480,
      trapFocus: false,
      labels: {
        confirm: 'Disconnect',
        cancel: 'Cancel'
      },
      confirmProps: { color: 'red' },
      children: (
        <Typography variant="body-lg">
          Disconnect Authorized Accounts will remove GitHub configuration from the Data App and will also disable Auto
          Sync & Deployment. Do you want to proceed?
        </Typography>
      ),
      onConfirm: async () => {
        await unlink.mutateAsync({
          orgId,
          projectId,
          appId: `${editApp?.id}`
        })
        refetch()
      }
    })
  }

  const topButton = (
    <Flex justify="space-between">
      <Typography variant="title-md">Connect to GitHub</Typography>
      <Flex gap={8}>
        <Button
          size="compact-xs"
          variant={linked ? 'default' : 'filled'}
          h={28}
          loading={isFetching || link.isLoading || unlink.isLoading}
          data-mp-event={`DataService ${linked ? 'disconnect' : 'connect'} to github button clicked`}
          onClick={() => {
            linked ? openUnlinkModal() : setOpened(true)
          }}
        >
          {linked ? 'Disconnect' : 'Connect'}
        </Button>
        {linked && (
          <ActionIcon
            variant="default"
            onClick={() => {
              setEditOpen(true)
            }}
          >
            <IconEdit05 size={14} />
          </ActionIcon>
        )}
      </Flex>
    </Flex>
  )

  const connectButtonEnable = useMemo(() => {
    return !directoryErrInfo && !isReposConflict && !!branch && !!directory
  }, [directory, branch, directoryErrInfo, isReposConflict])

  const clearStoreInfo = () => {
    clearCreateFormStorageDatas()
    setDirectoryErrInfo('')
    setIsReposConflict(false)
  }

  const connectSubmitHandler = async (values: FormValues, cb: () => void) => {
    if (!values.repository_id || !values.directory || !values.branch) {
      return
    }

    const repos = values.repository_id.split('-')
    await link.mutateAsync({
      orgId,
      projectId,
      appId: `${editApp?.id}`,
      data: {
        branch: values.branch,
        directory: values.directory,
        installation_id: (repos.length === 2 && +repos[1]) || 0,
        repository_id: (repos.length && +repos[0]) || 0,
        enable_automatic_deployment: values.enable_automatic_deployment
      }
    })
    refetch()
    updateDeployConfig()
    clearStoreInfo()

    cb()
  }

  const editModal = (
    <Modal
      title="Edit GitHub Connection"
      opened={editOpen}
      size={700}
      centered
      trapFocus={false}
      closeOnClickOutside={false}
      onClose={() => {
        setEditOpen(false)
        clearStoreInfo()
      }}
    >
      <Form
        layout="none"
        formMode="onChange"
        actionsProps={{
          confirmText: 'Confirm',
          disabled: !connectButtonEnable
        }}
        form={formProps}
        onSubmit={(values) =>
          connectSubmitHandler(
            {
              ...values,
              enable_automatic_deployment: dataappDeployConfig?.enable_automatic_deployment
            },
            () => {
              setEditOpen(false)
            }
          )
        }
        onCancel={() => {
          setEditOpen(false)
          clearStoreInfo()
        }}
      >
        <Repos
          authed={true}
          isCreate={false}
          defaultValue={{
            repository_id: `${linkInfo?.data?.repository_id}-${linkInfo?.data?.installation_id}`,
            branch: linkInfo?.data?.branch || '',
            directory: linkInfo?.data?.directory || ''
          }}
        />
      </Form>
    </Modal>
  )

  const connectModal = (
    <Modal
      title="Connect your Data App to GitHub"
      opened={opened}
      size={700}
      centered
      trapFocus={false}
      closeOnClickOutside={false}
      onClose={() => {
        setOpened(false)
        clearStoreInfo()
      }}
    >
      <Form
        layout="none"
        formMode="onChange"
        actionsProps={{
          confirmText: 'Confirm',
          disabled: !connectButtonEnable
        }}
        form={formProps}
        onSubmit={(values) =>
          connectSubmitHandler(values, () => {
            setOpened(false)
            notifier.success(
              'Your Data App has been successfully connected to GitHub! Now you can proceed with deploying your endpoints.',
              {
                autoClose: 5000
              }
            )
          })
        }
        onCancel={() => {
          setOpened(false)
          clearStoreInfo()
        }}
      >
        <GithubAuth isCreate={false}>
          <Alert mt={24} mb={24}>
            To synchronize the endpoints from the TiDB Cloud console to your GitHub directory, you are required to
            initiate a deployment operation.
            <br />
            If you are importing an existing data app from a GitHub repository, please follow the instructions provided
            <GithubDocument
              ml={4}
              text="here"
              link="https://docs.pingcap.com/tidbcloud/data-service-manage-github-connection#import-configurations-of-an-existing-data-app"
            />
            .
          </Alert>
        </GithubAuth>
      </Form>
    </Modal>
  )

  return (
    <>
      <Card pt={24} px={24} pb={6} h="100%" sx={{ display: 'flex', flexDirection: 'column' }}>
        {topButton}
        {isFetching ? (
          <Flex justify="center" mt={48}>
            <Loader />
          </Flex>
        ) : linked && linkInfo?.data?.repository_id ? (
          <LinkedRepo linkInfo={linkInfo.data} />
        ) : (
          <UnlinkedRepo linked={!!linked} />
        )}
      </Card>
      {connectModal}
      {editModal}
    </>
  )
}

export default GitHub
