import { ActionIcon, Box, Button, Group, Menu, Tooltip, Typography } from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useEffect, useMemo, useState } from 'react'
import { Link, useHistory } from 'react-router-dom'

import { ReasonHoverHint, type HoverHintReason } from 'dbaas/components/HoverHint/ReasonHoverHint'
import { HeroComponent } from 'dbaas/components/Measurement'
import { useAccessCheck, useAccessDeniedHintReason } from 'dbaas/contexts/access-control'
import { canEditChangefeed, getChangefeedDestinationName } from 'dbaas/features/Changefeed'
import { ChangefeedStatus } from 'dbaas/features/Changefeed/ChangefeedStatus'
import { usePremiumChangefeedActions } from 'dbaas/features/Changefeed/useChangefeedActions'
import { isClusterInvalid, TableFallback } from 'dbaas/screens/ClusterV2/components/PausedStatus'
import { SharedTiDB } from 'dbaas/screens/NextGen/shared/model/shared-tidb-state'
import { useSharedTiDBContext } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/tidb-context'
import { TiDBPageShell } from 'dbaas/screens/NextGen/tidb-mgmt-container/shared/TiDBPageShell'
import { Commonv1beta1ClusterState } from 'dbaas/services/api-clients/v2023/cluster-management/v1beta1/interface'
import { useNgListChangefeeds } from 'dbaas/services/dataflow'
import {
  ConsoleapiChangefeed,
  ConsoleapiChangefeedStatus,
  ConsoleapiChangefeedType
} from 'dbaas/services/dataflow/interface'
import useStores from 'dbaas/stores/useStores'
import { formatTime } from 'dbaas/utils/format'

const ChangefeedListHeader = ({ cluster }: { cluster: SharedTiDB }) => {
  const history = useHistory()
  const isInvalid = isClusterInvalid(cluster)
  const { reason: accessDeniedReason } = useAccessDeniedHintReason({
    id: 'TidbxCDCAction'
  })
  const invalidReason = useMemo<HoverHintReason>(
    () => ({
      id: 'clusterInvalid',
      when: isInvalid,
      content: `The function is unavailable in a ${cluster.state?.toLowerCase()} state.`
    }),
    [cluster.state, isInvalid]
  )

  return (
    <Group>
      <ReasonHoverHint reasons={[accessDeniedReason, invalidReason]}>
        {({ matched }) => (
          <Button
            size="sm"
            disabled={matched}
            onClick={() => history.push(`/tidbs/${cluster.tidbId}/changefeed/create`)}
          >
            Create Changefeed
          </Button>
        )}
      </ReasonHoverHint>
    </Group>
  )
}

const ChangefeedList = () => {
  const history = useHistory()
  const {
    store: { tenantData }
  } = useStores()
  const cluster = useSharedTiDBContext()
  const [pagination, setPagination] = useState<{
    pageIndex: number
    pageSize: number
  }>({
    pageIndex: 0,
    pageSize: 20
  })
  const { data, isLoading, refetch, isFetched } = useNgListChangefeeds(
    cluster.tidbId!,
    {
      page: pagination.pageIndex + 1,
      per_page: pagination.pageSize
    },
    {
      query: {
        enabled: !!cluster.tidbId && !isClusterInvalid(cluster),
        refetchInterval: 5000
      }
    }
  )

  useEffect(() => {
    if (!isLoading && pagination.pageIndex > 0 && data?.items?.length === 0) {
      setPagination((prev) => ({
        ...prev,
        pageIndex: prev.pageIndex - 1
      }))
    }
  }, [data?.items?.length, isLoading, pagination.pageIndex])

  const { handleScale, handlePause, handleResume, handleDelete, handleView, ConfirmModal } =
    usePremiumChangefeedActions({
      cluster,
      refetch
    })

  const actionAccessible = useAccessCheck('TidbxCDCAction')
  const columns: MRT_ColumnDef<ConsoleapiChangefeed>[] = [
    {
      header: 'ID',
      size: 120,
      Header: () => <Typography pl={16}>ID</Typography>,
      accessorFn: (changefeed) => {
        return (
          <Box component={Link} to={`/tidbs/${cluster.tidbId}/changefeed/${changefeed.changefeed_id}`} ml={16}>
            {changefeed.changefeed_id}
          </Box>
        )
      }
    },
    {
      header: 'Name',
      Header: () => <Typography>Name</Typography>,
      accessorFn: (changefeed) => {
        const displayName = changefeed.name || changefeed.request?.name || 'no name'
        return displayName
      }
    },
    {
      header: 'Destination',
      maxSize: 150,
      accessorFn: (changefeed) => {
        const destinationLabel = getChangefeedDestinationName(changefeed, cluster.cloudProvider)
        if (changefeed.changefeed_type === ConsoleapiChangefeedType.SERVERLESS_TIDB) {
          return (
            <Link to={`/clusters/${changefeed.request?.serverless_tidb_info?.cluster_id}`} target="_blank">
              {destinationLabel}
            </Link>
          )
        }
        return destinationLabel
      }
    },
    {
      header: 'Status',
      maxSize: 150,
      accessorFn: (changefeed) => {
        return (
          <Box sx={{ display: 'inline-block' }}>
            <ChangefeedStatus status={changefeed.status} error={changefeed.error} />
          </Box>
        )
      }
    },
    {
      header: 'Checkpoint Time',
      accessorFn: (changefeed) => {
        if (!changefeed.checkpoint_utc) {
          return '--'
        }

        const formatted = formatTime(changefeed.checkpoint_utc, { offset: tenantData.timezone })

        return (
          <Tooltip label={changefeed.checkpoint_tso}>
            <div>{formatted}</div>
          </Tooltip>
        )
      }
    },
    {
      header: 'Create Time',
      size: 230,
      accessorFn: (changefeed) => {
        return changefeed.created_at ? formatTime(changefeed.created_at, { offset: tenantData.timezone }) : '--'
      }
    },
    {
      id: 'Action',
      header: '',
      size: 60,
      accessorFn: (changefeed) => {
        const isPaused = changefeed.status === ConsoleapiChangefeedStatus.PAUSED
        const isRunning = changefeed.status === ConsoleapiChangefeedStatus.RUNNING
        const isError = changefeed.status === ConsoleapiChangefeedStatus.ERROR
        const isFailed = changefeed.status === ConsoleapiChangefeedStatus.FAILED
        const isWarning = changefeed.status === ConsoleapiChangefeedStatus.WARNING

        const handleScaleAction = () => {
          handleScale(changefeed)
        }
        const handlePauseAction = () => {
          handlePause(changefeed)
        }
        const handleResumeAction = () => {
          handleResume(changefeed)
        }
        const handleDeleteAction = () => {
          handleDelete(changefeed)
        }

        return (
          <Menu shadow="md" width={200}>
            <Menu.Target>
              <ActionIcon variant="subtle">
                <Box c="carbon.8" component={IconDotsHorizontal} size={18} />
              </ActionIcon>
            </Menu.Target>

            <Menu.Dropdown>
              {!cluster.computed.isEssentialV2 && (
                <Menu.Item
                  data-mp-event="View Changefeed detail Clicked"
                  onClick={() => {
                    handleView(changefeed)
                  }}
                >
                  View
                </Menu.Item>
              )}
              <Menu.Item
                disabled={
                  !actionAccessible ||
                  changefeed.status !== ConsoleapiChangefeedStatus.RUNNING ||
                  cluster.state === Commonv1beta1ClusterState.MAINTENANCE
                }
                data-mp-event="Open Changefeed Scale Up/Down Dialog Clicked"
                onClick={() => handleScaleAction()}
              >
                Scale Up/Down
              </Menu.Item>
              {!(isPaused || isFailed) && (
                <Menu.Item
                  disabled={!actionAccessible || !(isRunning || isError || isWarning)}
                  data-mp-event="Pause Changefeed Clicked"
                  onClick={() => handlePauseAction()}
                >
                  Pause
                </Menu.Item>
              )}
              {(isPaused || isFailed) && (
                <Menu.Item
                  disabled={!actionAccessible || !(isPaused || isFailed)}
                  data-mp-event="Resume Changefeed Clicked"
                  onClick={() => handleResumeAction()}
                >
                  Resume
                </Menu.Item>
              )}
              <Menu.Item
                disabled={!actionAccessible || !canEditChangefeed(changefeed)}
                data-mp-event="Edit Changefeed Clicked"
                onClick={() => history.push(`/tidbs/${cluster.tidbId}/changefeed/edit?id=${changefeed.changefeed_id}`)}
              >
                Edit
              </Menu.Item>
              {changefeed.status !== 'CREATING' && (
                <Menu.Item
                  disabled={!actionAccessible}
                  data-mp-event="Duplicate Changefeed Clicked"
                  onClick={() => {
                    history.push(`/tidbs/${cluster.tidbId}/changefeed/create?from_id=${changefeed.changefeed_id}`)
                  }}
                >
                  Duplicate
                </Menu.Item>
              )}
              <Menu.Item
                disabled={!actionAccessible}
                onClick={() => handleDeleteAction()}
                data-mp-event="Delete Changefeed Clicked"
              >
                Delete
              </Menu.Item>
            </Menu.Dropdown>
          </Menu>
        )
      }
    }
  ]

  return (
    <TiDBPageShell
      title="Changefeed"
      headerProps={{ withBack: false, rightSection: <ChangefeedListHeader cluster={cluster} /> }}
    >
      {isFetched && <HeroComponent />}
      <ProTable
        columns={columns}
        emptyMessage="No Changefeed"
        data={data?.items ?? []}
        loading={isLoading}
        manualPagination={true}
        state={{ pagination }}
        mantineTableProps={{
          highlightOnHover: false
        }}
        rowCount={data?.total || 0}
        onPaginationChange={(updater) => {
          setPagination((prev) => {
            const next = typeof updater === 'function' ? updater(prev) : updater
            return next.pageSize === prev.pageSize ? next : { ...next, pageIndex: 0 }
          })
        }}
        pagination={{
          showRowsPerPage: true,
          showTotal: true
        }}
        renderEmptyRowsFallback={() => (
          <TableFallback height="calc(100vh - 280px)">
            <TableFallback.Empty
              title="Get started by creating your first changefeed"
              desc="Changefeeds allow you to replicate change data from your TiDB Cloud to Kafka or other MySQL compatible databases."
            />
          </TableFallback>
        )}
      />

      {ConfirmModal}
    </TiDBPageShell>
  )
}

export default observer(ChangefeedList)
