import { Anchor, Button, Card, Stack, useMantineTheme } from '@tidbcloud/uikit'
import { Alert, Box, Typography } from '@tidbcloud/uikit'
import { IconAnnotationAlert, IconInfoCircle } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useEffect, useMemo, useState } from 'react'

import config from 'config'
import { HoverHintReason, ReasonHoverHint } from 'dbaas/components/HoverHint/ReasonHoverHint'
import { HeroComponent } from 'dbaas/components/Measurement'
import { useAccessCheck, useAccessDeniedHintReason } from 'dbaas/contexts/access-control'
import { ALERT_SUBSCRIBER_TYPE_LABELS } from 'dbaas/features/AlertSubscription'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { ClusterPageShell } from 'dbaas/screens/ClusterV2/components'
import SubscribersTable from 'dbaas/screens/NextGen/premium/alert-subscription/shared/SubscriberTable'
import { useListEssentialAlertSubscribers, useGetEssentialAlertSubscriberQuota } from 'dbaas/services/clinicService'
import {
  EntityAlertSubscribersItem,
  EntityAlertSubscriberType,
  EntitySupportPlanType
} from 'dbaas/services/clinicService/interface'
import useStores from 'dbaas/stores/useStores'

import { CreateModal } from './CreateModal'
import { DeleteModal } from './DeleteModal'

const SUBSCRIBE_TIPS: { [k: string]: JSX.Element } = {
  [EntityAlertSubscriberType.SLACK]: <>Please refer to documentation to learn how to set up.</>,
  [EntityAlertSubscriberType.ZOOM]: <>Please refer to documentation to learn how to set up.</>
}

const SUBSCRIBER_TYPES: { label: string; value: EntityAlertSubscriberType; tip?: JSX.Element }[] = Object.values(
  EntityAlertSubscriberType
).map((t) => ({
  label: ALERT_SUBSCRIBER_TYPE_LABELS[t],
  value: t,
  tip: SUBSCRIBE_TIPS[t]
}))

interface AlertsSubscriptionProps {
  cluster: SharedCluster
  showAddSubscriber: boolean
  closeAddSubscriber: () => void
}

const AlertsSubscription = observer(({ cluster, showAddSubscriber, closeAddSubscriber }: AlertsSubscriptionProps) => {
  const { colors } = useMantineTheme()
  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const orgId = tenantData.id
  const clusterId = cluster.id

  const { isFetched, isLoading, refetch, data } = useListEssentialAlertSubscribers(orgId, activeProjectId, clusterId)
  const [selectedSubscriber, setSelectedSubscriber] = useState<EntityAlertSubscribersItem | null>(null)
  const accessible = useAccessCheck('TidbxAlertSubscriptionAction')
  const dataByType = useMemo(() => {
    if (!data) {
      return undefined
    }
    return SUBSCRIBER_TYPES.map((t) => ({
      ...t,
      data: data.alertSubscribers?.filter((d) => d.subscriberType === t.value)
    }))
  }, [data])

  const noData = dataByType?.every((group) => !group.data?.length)

  return (
    <Stack gap="xl">
      {isFetched && <HeroComponent />}

      <Alert icon={<IconInfoCircle size={12} />} color="peacock">
        By subscribing to email alerts, you can receive notifications for alerts from TiDB Cloud. Refer to{' '}
        <Anchor
          href="https://docs.pingcap.com/tidbcloud/monitor-built-in-alerting"
          target="_blank"
          rel="noreferrer"
          data-mp-event="Alert Subscription Documentation Link Clicked"
          data-mp-source="Alerts"
        >
          TiDB Cloud Built-in Alerting
        </Anchor>{' '}
        to learn what alerts come with TiDB Cloud and what actions you may want to take when you receive an alert.
      </Alert>

      <Box>
        {noData && (
          <Stack justify="center" align="center" mih={512}>
            <IconAnnotationAlert size={48} color={colors.carbon[7]} />
            <Typography variant="title-lg" fz={18} c="carbon.7">
              Get started by adding subscriber
            </Typography>
            <Typography variant="body-lg" c="carbon.7" w={300} sx={{ textAlign: 'center' }}>
              Alert subscription is used to send system notifications to subscribers.
            </Typography>
          </Stack>
        )}
        <Stack gap="xl">
          {dataByType?.map((group) =>
            !!group.data?.length ? (
              <Card p="xl" key={group.value}>
                <Stack>
                  <Stack gap={4}>
                    <Typography variant="title-lg">{group.label}</Typography>
                    {!!group.tip && (
                      <Typography variant="body-lg" c="carbon.7">
                        {group.tip}
                      </Typography>
                    )}
                  </Stack>
                  <SubscribersTable
                    accessible={accessible}
                    showActions={accessible}
                    tidbEntityName="instance"
                    type={group.value}
                    subscribers={group.data || []}
                    unsubscribe={setSelectedSubscriber}
                    loading={isLoading}
                  />
                </Stack>
              </Card>
            ) : (
              <></>
            )
          )}
        </Stack>
      </Box>

      <CreateModal
        opened={showAddSubscriber}
        orgId={orgId}
        projectId={activeProjectId}
        clusterId={clusterId}
        cluster={cluster}
        onCancel={closeAddSubscriber}
        onSuccess={() => {
          closeAddSubscriber()
          refetch()
        }}
      />

      <DeleteModal
        opened={!!selectedSubscriber}
        orgId={orgId}
        projectId={activeProjectId}
        clusterId={clusterId}
        subscriber={selectedSubscriber}
        onCancel={() => setSelectedSubscriber(null)}
        onDelete={() => {
          setSelectedSubscriber(null)
          refetch()
        }}
      />
    </Stack>
  )
})

interface AlertSubscriptionPageProps {
  cluster: SharedCluster
}

const AlertSubscriptionPage = observer(({ cluster }: AlertSubscriptionPageProps) => {
  useEffect(() => {
    document.title = `${config.PAGE_TITLE_PREFIX}Alert Subscription`
  }, [])

  const [showAddSubscriber, setShowAddSubscriber] = useState(false)
  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const orgId = tenantData.id
  const clusterId = cluster.id

  const { isLoading, data } = useListEssentialAlertSubscribers(orgId, activeProjectId, clusterId)
  const { data: quotaData, isLoading: isQuotaLoading } = useGetEssentialAlertSubscriberQuota(
    orgId,
    activeProjectId,
    clusterId
  )
  // default to false if quotaData is not available
  const isOverQuotaLimit =
    quotaData?.maxAlertSubscribersCount !== undefined &&
    (data?.totalSize || 0) >= (quotaData?.maxAlertSubscribersCount || 0)
  const canUseExternalSubscription =
    quotaData?.supportPlan === EntitySupportPlanType.Enterprise ||
    quotaData?.supportPlan === EntitySupportPlanType.Premium
  const isCreateDisabled = isLoading || isQuotaLoading || isOverQuotaLimit

  const unavailable = cluster.computed.paused || cluster.computed.resuming || cluster.computed.pausing
  const clusterReady = cluster.computed.ready
  const clusterState = cluster.state?.toLowerCase() || 'unavailable'

  const { accessible, reason: accessDeniedReason } = useAccessDeniedHintReason({
    id: 'TidbxAlertSubscriptionAction'
  })

  const notReadyReason = useMemo<HoverHintReason>(
    () => ({
      id: 'notReady',
      when: !clusterReady || unavailable,
      content: `This feature is unavailable while the instance is ${clusterState}.`
    }),
    [clusterReady, unavailable, clusterState]
  )

  const quotaLimitReason = useMemo<HoverHintReason>(
    () => ({
      id: 'quotaLimit',
      when: isOverQuotaLimit,
      content: (
        <Typography variant="body-md" c="carbon.7">
          The number of created alert subscribers has reached the limit.
          {canUseExternalSubscription ? (
            <>
              {' '}
              If needed, please contact{' '}
              <Anchor
                href="https://docs.pingcap.com/tidbcloud/tidb-cloud-support"
                target="_blank"
                rel="noreferrer"
                data-mp-event="Technical Support Documentation Link Clicked"
                data-mp-source="Alerts"
              >
                technical support
              </Anchor>{' '}
              to adjust the quota.
            </>
          ) : (
            ''
          )}
        </Typography>
      ),
      hoverCardProps: {
        width: 400
      }
    }),
    [canUseExternalSubscription, isOverQuotaLimit]
  )

  return (
    <ClusterPageShell
      title="Alert Subscription"
      headerProps={{
        rightSection: (
          <ReasonHoverHint reasons={[accessDeniedReason, notReadyReason, quotaLimitReason]}>
            <Button
              data-mp-event="Alerts Subscription Subscribe Button Clicked"
              size="sm"
              onClick={() => setShowAddSubscriber(true)}
              disabled={!accessible || !clusterReady || unavailable || isCreateDisabled}
            >
              Add Subscriber
            </Button>
          </ReasonHoverHint>
        )
      }}
    >
      <AlertsSubscription
        cluster={cluster}
        showAddSubscriber={showAddSubscriber}
        closeAddSubscriber={() => setShowAddSubscriber(false)}
      />
    </ClusterPageShell>
  )
})

export default AlertSubscriptionPage
