import {
  ActionIcon,
  Box,
  Button,
  closeAllModals,
  Group,
  HoverCard,
  Menu,
  Modal,
  notifier,
  openModal,
  Stack,
  Text,
  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 { ReactNode, useState } from 'react'
import { Link, useHistory } from 'react-router-dom'

import { HeroComponent } from 'dbaas/components/Measurement'
import { AccessCheck, AccessDeniedHoverHint } from 'dbaas/contexts/access-control'
import { canEditChangefeed, ChangefeedNames } from 'dbaas/features/Changefeed'
import { ChangefeedStatus } from 'dbaas/features/Changefeed/ChangefeedStatus'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { isClusterInvalid, TableFallback } from 'dbaas/screens/ClusterV2/components/PausedStatus'
import { useDeleteConnector, useListConnectors, useStartConnector, useStopConnector } from 'dbaas/services/dataflow'
import { DataflowConnector, DataflowConnectorType } from 'dbaas/services/dataflow/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { formatTime } from 'dbaas/utils/format'

import { ChangefeedScale } from './ChangefeedScale'

export const ChangefeedListHeader = ({ cluster }: { cluster: SharedCluster }) => {
  const history = useHistory()
  const isInvalid = isClusterInvalid(cluster)
  return (
    <Group>
      <AccessDeniedHoverHint id="ClusterCDCAction">
        {({ accessible }) => (
          <HoverCard shadow="md" withArrow disabled={!isInvalid || !accessible}>
            <HoverCard.Target>
              <div>
                <Button
                  size="sm"
                  disabled={isInvalid || !accessible}
                  onClick={() => history.push(`/clusters/${cluster.id}/changefeed/create-changefeed`)}
                  data-mp-event="mp-createchangefeed-1691461016002"
                >
                  Create Changefeed
                </Button>
              </div>
            </HoverCard.Target>
            <HoverCard.Dropdown>
              The function is unavailable in a {cluster.state.toLowerCase()} state.
            </HoverCard.Dropdown>
          </HoverCard>
        )}
      </AccessDeniedHoverHint>
    </Group>
  )
}

const renderChangefeedListFallback = (cluster: SharedCluster) => {
  if (isClusterInvalid(cluster)) {
    return (
      <TableFallback>
        <TableFallback.Paused
          cluster={cluster}
          featureName="Changefeed"
          featureDesc="Changefeeds allow you to replicate change data from your TiDB Cloud Dedicated cluster to Kafka, Object Storage, or other MySQL compatible databases."
        />
      </TableFallback>
    )
  }

  return (
    <TableFallback>
      <TableFallback.Empty
        title="Get started by creating your first changfeed"
        desc="Changefeeds allow you to replicate change data from your TiDB Cloud Dedicated cluster to Kafka, Object Storage, or other MySQL compatible databases."
      />
    </TableFallback>
  )
}

const ChangefeedList = ({ cluster }: { cluster: SharedCluster }) => {
  const history = useHistory()
  const {
    store: { tenantData, activeProjectId }
  } = useStores()

  const [pagination, setPagination] = useState<{
    pageIndex: number
    pageSize: number
  }>({
    pageIndex: 0,
    pageSize: 10
  })
  const { data, isLoading, refetch, isFetched } = useListConnectors(
    tenantData.id,
    activeProjectId,
    cluster?.id,
    {
      page: pagination.pageIndex + 1,
      per_page: pagination.pageSize
    },
    {
      query: {
        enabled: !isClusterInvalid(cluster),
        refetchInterval: 5000
      }
    }
  )

  const [confirmModal, setConfirmModal] = useState<{
    open: boolean
    connector?: DataflowConnector
    title?: ReactNode
    children?: ReactNode
    onConfirm?: () => void
  }>({
    open: false
  })
  const deleteConnector = useDeleteConnector()
  const pauseConnector = useStopConnector()
  const resumeConnector = useStartConnector()

  const handlePauseConnector = async (data: DataflowConnector) => {
    try {
      await pauseConnector.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: cluster.id,
        connectorId: data.connector_id,
        data: {}
      })
      notifier.success('Changefeed paused successfully')
      setConfirmModal({ open: false })
      await refetch()
    } catch (error) {
      notifier.error(getErrorMessage(error))
    }
  }
  const handleDeleteConnector = async (data: DataflowConnector) => {
    try {
      await deleteConnector.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: cluster.id,
        connectorId: data.connector_id
      })
      notifier.success('Changefeed deleted successfully')
      setConfirmModal({ open: false })
      await refetch()
    } catch (error) {
      notifier.error(getErrorMessage(error))
    }
  }
  const handleResumeConnector = async (data: DataflowConnector) => {
    try {
      notifier.success('Changefeed is resuming...')
      await resumeConnector.mutateAsync({
        orgId: tenantData.id,
        projectId: activeProjectId,
        clusterId: cluster.id,
        connectorId: data.connector_id,
        data: {}
      })
      setConfirmModal({ open: false })
      notifier.success('Changefeed resumed successfully')
      await refetch()
    } catch (error) {
      notifier.error(getErrorMessage(error))
    }
  }

  const columns: MRT_ColumnDef<DataflowConnector>[] = [
    {
      header: 'ID',
      size: 120,
      Header: () => <Typography pl={16}>ID</Typography>,
      accessorFn: (data) => {
        return (
          <Box component={Link} to={`/clusters/${cluster?.id}/changefeed/${data.connector_id}`} ml={16}>
            {data.connector_id}
          </Box>
        )
      }
    },
    {
      header: 'Name',
      Header: () => <Typography>Name</Typography>,
      accessorKey: 'name'
    },
    {
      header: 'Destination',
      maxSize: 150,
      accessorFn: (data) => {
        const name = `${ChangefeedNames[data.connector_type]}`
        if (data.connector_type === DataflowConnectorType.SERVERLESS_TIDB) {
          return (
            <Link to={`/clusters/${data.request?.serverless_tidb_info?.cluster_id}`} target="_blank">
              {name}
            </Link>
          )
        }
        return name
      }
    },
    {
      header: 'Status',
      maxSize: 150,
      accessorFn: (data) => {
        return (
          <Box sx={{ display: 'inline-block' }}>
            <ChangefeedStatus status={data.status} error={data.error} />
          </Box>
        )
      }
    },
    {
      header: 'Checkpoint Time',
      accessorFn: (data) => {
        return (
          <Tooltip label={data.checkpoint_tso}>
            <div>{formatTime(data.checkpoint_utc!, { offset: tenantData.timezone })}</div>
          </Tooltip>
        )
      }
    },
    {
      header: 'Create Time',
      size: 230,
      accessorFn: (data) => {
        return formatTime(data.created_at!, { offset: tenantData.timezone })
      }
    },
    {
      id: 'Action',
      header: '',
      size: 60,
      accessorFn: (data) => {
        const isDualRegion = data.connector_type === DataflowConnectorType.TIDB
        const isPaused = data.status === 'PAUSED'
        const isRunning = data.status === 'RUNNING'
        const isError = data.status === 'ERROR'
        const isFailed = data.status === 'FAILED'
        const isWarning = data.status === 'WARNING'

        const handleScale = () => {
          openModal({
            title: (
              <Text c="carbon.9" fw={700} fz={16}>
                Scale Up/Down
              </Text>
            ),
            centered: true,
            size: 630,
            children: <ChangefeedScale connector={data} onCancel={closeAllModals} onConfirm={closeAllModals} />
          })
        }
        const handlePause = async () => {
          setConfirmModal({
            open: true,
            connector: data,
            title: `Confirm to pause ${data.name || data.request?.name || `changefeed ${data.connector_id}`}?`,
            children: (
              <div>
                <Typography variant="body-lg">
                  Please avoid pausing the changefeed for more than 24 hours, as data changes that occurred during this
                  period will be garbage collected by TiDB and cannot be synchronized to downstream anymore.
                </Typography>
                <Typography variant="body-lg">
                  To prevent failure, please resume the changefeed <b>within 24 hours</b>. If it exceeds the 24-hour
                  limit, the only option is to delete the failed changefeed and recreate it to restore the original data
                  synchronization pipeline.
                </Typography>
              </div>
            ),
            onConfirm: () => {
              handlePauseConnector(data)
            }
          })
        }
        const handleResume = async () => {
          handleResumeConnector(data)
        }
        const handleDelete = () => {
          setConfirmModal({
            open: true,
            connector: data,
            title: `Confirm to delete ${data.name || data.request?.name || `changefeed ${data.connector_id}`}?`,
            children: (
              <Typography variant="body-lg">
                Once a changefeed is deleted, it cannot be recovered, confirm to delete?
              </Typography>
            ),
            onConfirm: () => {
              handleDeleteConnector(data)
            }
          })
        }

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

            <Menu.Dropdown>
              <Menu.Item
                data-mp-event="View Changefeed detail Clicked"
                onClick={() => {
                  history.push(`/clusters/${cluster?.id}/changefeed/${data.connector_id}`)
                }}
              >
                View
              </Menu.Item>
              <AccessCheck id="ClusterCDCAction">
                {({ accessible }) => (
                  <>
                    {!isDualRegion && (
                      <Menu.Item
                        disabled={!accessible || data.status !== 'RUNNING' || cluster.state === 'MAINTENANCE'}
                        data-mp-event="Open Changefeed Scale Up/Down Dialog Clicked"
                        onClick={handleScale}
                      >
                        Scale Up/Down
                      </Menu.Item>
                    )}
                    {!isDualRegion && (
                      <Menu.Item
                        disabled={!accessible || !(isRunning || isError || isWarning)}
                        data-mp-event="Pause Changefeed Clicked"
                        onClick={handlePause}
                      >
                        Pause
                      </Menu.Item>
                    )}
                    {!isDualRegion && (
                      <Menu.Item
                        disabled={!accessible || !(isPaused || isFailed)}
                        data-mp-event="Resume Changefeed Clicked"
                        onClick={handleResume}
                      >
                        Resume
                      </Menu.Item>
                    )}
                    {!isDualRegion && (
                      <Menu.Item
                        disabled={!accessible || !canEditChangefeed(data)}
                        data-mp-event="Edit Changefeed Clicked"
                        onClick={() =>
                          history.push(`/clusters/${cluster.id}/changefeed/edit-changefeed?id=${data.connector_id}`)
                        }
                      >
                        Edit
                      </Menu.Item>
                    )}
                    {data.status !== 'CREATING' && (
                      <Menu.Item
                        disabled={!accessible}
                        data-mp-event="Duplicate Changefeed Clicked"
                        onClick={() => {
                          history.push(
                            `/clusters/${cluster.id}/changefeed/create-changefeed?from_id=${data.connector_id}`
                          )
                        }}
                      >
                        Duplicate
                      </Menu.Item>
                    )}
                    <Menu.Item disabled={!accessible} onClick={handleDelete} data-mp-event="Delete Changefeed Clicked">
                      Delete
                    </Menu.Item>
                  </>
                )}
              </AccessCheck>
            </Menu.Dropdown>
          </Menu>
        )
      }
    }
  ]

  return (
    <div>
      {isFetched && <HeroComponent />}
      <ProTable
        columns={columns}
        emptyMessage="No Changefeed"
        data={data?.items ?? []}
        loading={isLoading}
        manualPagination={true}
        state={{ pagination }}
        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
        }}
        mantinePaperProps={{ mx: 24 }}
        renderEmptyRowsFallback={() => renderChangefeedListFallback(cluster)}
        mantineTableProps={{
          highlightOnHover: false
        }}
      />

      <Modal
        opened={confirmModal.open}
        size="lg"
        onClose={() => setConfirmModal({ open: false })}
        title={confirmModal.title}
      >
        <Stack>
          {confirmModal.children}

          <Group justify="flex-end">
            <Button variant="default" onClick={() => setConfirmModal({ open: false })}>
              Cancel
            </Button>
            <Button
              loading={pauseConnector.isLoading || resumeConnector.isLoading || deleteConnector.isLoading}
              onClick={confirmModal?.onConfirm}
              color="red"
              variant="light"
            >
              I understand, continue
            </Button>
          </Group>
        </Stack>
      </Modal>
    </div>
  )
}

export default observer(ChangefeedList)
