import { Flex, HoverCard, Typography } from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconInfoCircle } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useEffect, useMemo, useState } from 'react'

import config from 'config'
import { HeroComponent } from 'dbaas/components/Measurement'
import { AccessGuard, PageAccessGuard, useAccessCheck } from 'dbaas/contexts/access-control'
import { SharedCluster } from 'dbaas/features/ClusterManagement/cluster'
import { useSQLUsersEnabled } from 'dbaas/features/ClusterManagement/feats'
import { ClusterPageShell } from 'dbaas/screens/ClusterV2/components'
import { useListSqlUsers } from 'dbaas/services/account'
import { CentralSqlUser } from 'dbaas/services/account/interface'
import useStores from 'dbaas/stores/useStores'

import { TableFallback } from '../../components/PausedStatus'

import { SQLUserActions } from './Action'
import { CreateSQLUser, SQL_USER_BUIlTIN_ROLES_LABELS } from './Edit'

const RoleHeader = () => {
  return (
    <Flex align="center" sx={{ zIndex: 10 }}>
      <Typography variant="label-lg" c="carbon.9">
        Role
      </Typography>{' '}
      <HoverCard width={350} withArrow shadow="md">
        <HoverCard.Target>
          <IconInfoCircle size={16} ml={4} />
        </HoverCard.Target>
        <HoverCard.Dropdown>
          <Typography variant="body-lg">
            A role is a named collection of privileges and grants SQL user privileges to perform a set of actions on
            database objects.
          </Typography>
        </HoverCard.Dropdown>
      </HoverCard>
    </Flex>
  )
}

const SQLUsersPanel: React.FC<React.PropsWithChildren<{ cluster: SharedCluster }>> = observer(({ cluster }) => {
  useEffect(() => {
    document.title = `${config.PAGE_TITLE_PREFIX}SQL Users`
  }, [])
  const actionAccessCheckProps = cluster.computed.isServerless
    ? {
        id: 'TidbxSQLUsersAction' as const
      }
    : {
        id: 'ClusterSQLUsersAction' as const
      }
  const pageAccessCheckProps = cluster.computed.isServerless
    ? {
        id: 'TidbxRead' as const
      }
    : {
        id: 'ClusterSQLUsersGate' as const
      }
  const editable = useAccessCheck(actionAccessCheckProps.id)

  const {
    store: { tenantData, activeProjectId }
  } = useStores()
  const [currentPage, setCurrentPage] = useState(1)
  const pageSize = 10

  const { enabled: enabledSQLUsers } = useSQLUsersEnabled(cluster)
  const unavailable = cluster.computed.paused || cluster.computed.resuming || cluster.computed.pausing
  const entityName = cluster.computed.isDedicated ? 'cluster' : 'instance'

  const { data, refetch, isLoading, isFetched } = useListSqlUsers(
    tenantData.id,
    activeProjectId,
    cluster.id,
    {
      page: currentPage,
      page_size: pageSize
    },
    {
      query: {
        enabled: !!(tenantData.id && activeProjectId && cluster.id && enabledSQLUsers && !unavailable)
      }
    }
  )

  const columns = useMemo(() => {
    const columns: MRT_ColumnDef<CentralSqlUser>[] = [
      {
        header: '',
        Header: (
          <Typography variant="label-lg" c="carbon.9">
            SQL User Name
          </Typography>
        ),
        accessorKey: 'id',
        accessorFn: (originalRow) => {
          return (
            <Typography variant="label-lg" c="carbon.8">
              {originalRow.user_name}
            </Typography>
          )
        },
        mantineTableBodyCellProps: {
          pl: 24
        }
      },
      {
        header: '',
        Header: (
          <Typography variant="label-lg" c="carbon.9">
            Authentication Method
          </Typography>
        ),
        accessorKey: 'auth_method',
        accessorFn(originalRow) {
          return <Typography variant="body-lg">{originalRow.auth_method}</Typography>
        }
      },
      {
        header: 'role',
        Header: <RoleHeader />,
        accessorFn(originalRow) {
          const roles: string[] = []
          if (originalRow.builtin_role) {
            roles.push(
              SQL_USER_BUIlTIN_ROLES_LABELS[originalRow.builtin_role.replace(`${cluster.serverless?.userPrefix}.`, '')]
            )
          }
          if (originalRow.custom_role?.length) {
            roles.push(originalRow.custom_role.join(', '))
          }
          return <Typography variant="body-lg">{roles.length ? roles.join(', ') : 'NONE'}</Typography>
        }
      },
      {
        id: 'action',
        header: 'Action',
        Header: (
          <Typography variant="label-lg" c="carbon.9">
            Action
          </Typography>
        ),
        accessorKey: 'action',
        size: 20,
        accessorFn(originalRow) {
          return (
            <SQLUserActions
              sqlUser={originalRow}
              clusterId={cluster.id}
              isServerless={cluster.computed.isServerless}
              token={`${cluster.serverless?.userPrefix}.`}
              onUpdate={refetch}
              onDelete={() => {
                setCurrentPage(1)
                refetch()
              }}
            />
          )
        }
      }
    ]
    return columns
  }, [cluster, refetch])

  return (
    <ClusterPageShell
      title="SQL Users"
      headerProps={{
        withBack: false,
        rightSection: (
          <AccessGuard {...actionAccessCheckProps}>
            <HoverCard shadow="md" withArrow disabled={!unavailable}>
              <HoverCard.Target>
                <div>
                  <CreateSQLUser
                    disabled={!enabledSQLUsers || unavailable}
                    clusterId={cluster.id}
                    isServerless={cluster.computed.isServerless}
                    token={`${cluster.serverless?.userPrefix}.`}
                    onCreate={() => {
                      // reset page
                      setCurrentPage(1)
                      refetch()
                    }}
                  />
                </div>
              </HoverCard.Target>
              <HoverCard.Dropdown>
                The function is unavailable in a {cluster.state.toLowerCase()} state.
              </HoverCard.Dropdown>
            </HoverCard>
          </AccessGuard>
        )
      }}
      bodyProps={{
        px: 0,
        mb: 80
      }}
    >
      <PageAccessGuard
        {...pageAccessCheckProps}
        fallback={(defaultFallback) => (
          <>
            {defaultFallback}
            <HeroComponent />
          </>
        )}
      >
        <>
          <ProTable
            columns={columns}
            loading={isLoading}
            mantineTableProps={{
              horizontalSpacing: 24,
              verticalSpacing: 8,
              highlightOnHover: cluster.computed.paused ? false : true,
              sx: () => ({
                'thead tr th': {
                  paddingTop: 14,
                  paddingBottom: 14
                }
              })
            }}
            mantinePaperProps={{ mx: 24 }}
            renderEmptyRowsFallback={() => {
              if (unavailable) {
                return (
                  <TableFallback>
                    <TableFallback.Paused
                      cluster={cluster}
                      featureName="SQL Users"
                      featureDesc={`SQL Users allows you to manage SQL users on your ${entityName} and modify their passwords and roles.`}
                    />
                  </TableFallback>
                )
              }
              return undefined
            }}
            emptyMessage="No Data"
            data={cluster.computed.paused ? [] : data?.items || []}
            manualPagination={true}
            state={{ columnVisibility: { action: editable } }}
            pagination={
              data?.total
                ? {
                    total: Math.ceil((data?.total || 0) / 10) || 0,
                    value: currentPage || 1,
                    onChange: (page) => {
                      setCurrentPage(page)
                    }
                  }
                : undefined
            }
          />
          {isFetched && <HeroComponent />}
        </>
      </PageAccessGuard>
    </ClusterPageShell>
  )
})

export default SQLUsersPanel
