import { notifier } from '@tidbcloud/uikit'
import { Alert, Box, Button, Flex, Group, Modal, Typography } from '@tidbcloud/uikit'
import { Form, FormRadioGroup } from '@tidbcloud/uikit/biz'
import { IconCheckCircle, IconMinusCircle } from '@tidbcloud/uikit/icons'
import { isNil } from 'lodash-es'
import { useEffect } from 'react'
import { useFormContext } from 'react-hook-form'

import { useUpdateDataappDeployConfig, useIsGithubLinked } from 'dbaas/services/dataservice'

import { useDataApiContext } from '../../context'

interface FormValues {
  deployOption: number
}

// Serialize data using binary
const enum DeployOptionEnum {
  Both = 3,
  OnlyDraft = 2,
  None = 0
}

const enum BitEnum {
  ReviewDraftBit = 1 << 1,
  AutomaticDeploymentBit = 1 << 0
}

const deployOptionConfig = [DeployOptionEnum.Both, DeployOptionEnum.OnlyDraft, DeployOptionEnum.None]
const binary2Boolean = (v: number, bit: number) => (v & bit) === bit
const boolean2Binary = (reviewDraft?: boolean, automaticDeployment?: boolean) => {
  if (isNil(reviewDraft) || isNil(automaticDeployment)) return
  let value = 0
  reviewDraft && (value |= BitEnum.ReviewDraftBit)
  automaticDeployment && (value |= BitEnum.AutomaticDeploymentBit)
  return value
}

const DeployOptions = ({ linked }: { linked: boolean }) => {
  const { watch, setValue } = useFormContext()
  const { dataappDeployConfig } = useDataApiContext()

  useEffect(() => {
    setValue(
      'deployOption',
      boolean2Binary(
        dataappDeployConfig?.enable_ui_drafts,
        dataappDeployConfig?.enable_automatic_deployment
      )?.toString()
    )
  }, [dataappDeployConfig?.enable_ui_drafts, dataappDeployConfig?.enable_automatic_deployment])

  const value = watch('deployOption')

  return (
    <FormRadioGroup
      name="deployOption"
      value={value}
      data={deployOptionConfig.map((v) => ({
        label: (
          <Flex gap={5}>
            <DeployBadge enabled={binary2Boolean(v, BitEnum.AutomaticDeploymentBit)} name="Auto Sync & Deployment" />
            <DeployBadge enabled={binary2Boolean(v, BitEnum.ReviewDraftBit)} name="Review Draft" />
          </Flex>
        ),
        value: v + '',
        disabled: v === DeployOptionEnum.Both && !linked
      }))}
      direction="column"
    />
  )
}

export const DeployBadge = ({ enabled, name }: { enabled: boolean; name: string }) => {
  return (
    <Flex
      align="center"
      gap={2}
      py={2}
      px={6}
      h={20}
      sx={(theme) => ({ border: `1px solid ${theme.colors.carbon[5]}`, borderRadius: 8 })}
    >
      {enabled ? (
        <Box component={IconCheckCircle} size={12} c="green.7"></Box>
      ) : (
        <Box component={IconMinusCircle} size={12} c="carbon.6"></Box>
      )}
      <Typography variant="label-sm">{name}</Typography>
    </Flex>
  )
}

const Caption = () => {
  return (
    <>
      <Box>
        <Typography variant="action-sm" c="carbon.7" span mr={3}>
          Auto Sync & Deployment:
        </Typography>
        <Typography variant="body-sm" span>
          By enabling this configuration, commits pushed to GitHub will be automatically synchronized to TiDB Cloud
          console and deployed, and changes made via TiDB Cloud console will also be pushed to GitHub automatically
          after deployment.
        </Typography>
      </Box>
      <Box>
        <Typography variant="action-sm" c="carbon.7" span mr={3}>
          Review Draft:
        </Typography>
        <Typography variant="body-sm" span>
          By enabling this configuration, any changes made to this data application through TiDB Cloud console will be
          prompt to review before deployment.
        </Typography>
      </Box>
    </>
  )
}

const AlertInfo = () => {
  const { getValues } = useFormContext()
  const deployOption = getValues().deployOption
  if (isNil(deployOption)) return null
  switch (+deployOption) {
    case DeployOptionEnum.Both:
      return (
        <Alert>
          Enabling the "Auto Sync & Deployment" configuration <b>REQUIRES</b> enabling the "Review Draft" configuration
          as well. The purpose of "Review Draft" is to act as a gatekeeper, ensuring that only reviewed changes are
          permitted to be "auto pushed" to a GitHub repository. This is critical for maintaining the quality and
          stability of production changes.
        </Alert>
      )
    case DeployOptionEnum.OnlyDraft:
      return (
        <Alert color="yellow">
          By disabling only the "Auto Sync & Deployment" configuration, the TiDB Cloud console will no longer
          synchronize changes with the specified GitHub repository. However, the review process will still be in effect
          for changes made through the TiDB Cloud console. This is applicable in scenarios such as testing purposes or
          manual deployments.
        </Alert>
      )
    case DeployOptionEnum.None:
      return (
        <Alert color="yellow">
          By disabling both configurations, any modifications made to your application through the TiDB Cloud console
          will be deployed immediately, without undergoing the mandatory review process and without synchronization with
          GitHub.
        </Alert>
      )
    default:
      return null
  }
}

const ActionBtns = ({ loading, close }: { loading: boolean; close: () => void }) => {
  return (
    <Group justify="flex-end">
      <Button variant="default" onClick={close} data-mp-event="mp-cancel-1691461016868">
        Cancel
      </Button>
      <Button type="submit" loading={loading} data-mp-event="mp-confirm-1691461016870">
        Confirm
      </Button>
    </Group>
  )
}

const DeployConfig = ({ opened, onClose }: { opened: boolean; onClose: () => void }) => {
  const { orgId, projectId, editApp } = useDataApiContext()
  const updateConfigMutation = useUpdateDataappDeployConfig()

  const updateConfig = async (values: FormValues) => {
    const res = await updateConfigMutation.mutateAsync({
      orgId,
      projectId,
      appId: `${editApp?.id}`,
      data: {
        enable_ui_drafts: binary2Boolean(values.deployOption, BitEnum.ReviewDraftBit),
        enable_automatic_deployment: binary2Boolean(values.deployOption, BitEnum.AutomaticDeploymentBit)
      }
    })
    if (res.code !== 200) {
      notifier.error(res.message)
    } else {
      onClose()
    }
  }

  const { data } = useIsGithubLinked(orgId, projectId, `${editApp?.id}`, {
    query: {
      enabled: !!orgId && !!projectId && !!editApp?.id,
      refetchInterval: false,
      refetchOnWindowFocus: false
    }
  })

  return (
    <Modal opened={opened} title="Deployment Configuration" centered size={560} onClose={onClose}>
      <Form withActions={false} onSubmit={updateConfig}>
        <Caption />
        <DeployOptions linked={data?.data?.authorized || false} />
        <AlertInfo />
        <ActionBtns loading={updateConfigMutation.isLoading} close={onClose} />
      </Form>
    </Modal>
  )
}

export default DeployConfig
