import { ActionIcon, Alert, Box, Button, Group, Menu, SegmentedControl, Select, Typography } from '@tidbcloud/uikit'
import { MRT_ColumnDef, ProTable } from '@tidbcloud/uikit/biz'
import { IconDotsHorizontal } from '@tidbcloud/uikit/icons'
import { useMemoizedFn } from 'ahooks'
import { observer } from 'mobx-react'
import { useMemo, useState } from 'react'

import { HeroComponent } from 'dbaas/components/Measurement'
import { AccessDeniedHoverHint, useAccessCheck } from 'dbaas/contexts/access-control'
import { PageShell } from 'dbaas/layouts/v5/page'
import { queryClient } from 'dbaas/reactQueryClient'
import { getListProjectOpenAPIKeysQueryKey, useListProjectOpenAPIKeys } from 'dbaas/services/account'
import useStores from 'dbaas/stores/useStores'

import { ScopeTypeConst, ScopeTypes } from '../UserAccess/helpers'

import { CreationModal, ProjectAPIKeyCreationModal } from './CreationModal'
import { DeletionConfirm } from './DeletionConfirm'
import { EditModal } from './EditModal'
import { APIKeyItem, getAPIKeyRoleName, getPrivateKeyDisplay, useAPIKeyList, useAPIKeysV2 } from './helpers'
import { mpEvents } from './tracker'
import { ViewModal } from './ViewModal'

const DEFAULT_PAGE_SIZE = 10

export const ProjectAPIKeys = observer(
  ({
    projectId,
    orgId,
    currentPage,
    onPageChange
  }: {
    projectId: string
    orgId: string
    currentPage: number
    onPageChange: (page: number) => void
  }) => {
    const { data, isLoading, refetch } = useListProjectOpenAPIKeys(orgId, projectId, {
      page: currentPage,
      per_page: DEFAULT_PAGE_SIZE
    })

    const [editKey, setEditKey] = useState<APIKeyItem | null>(null)
    const [deleteKey, setDeleteKey] = useState<APIKeyItem | null>(null)

    const actionsAccessible = useAccessCheck('OrgAPIKeysAction')
    const columns = useMemo<MRT_ColumnDef<APIKeyItem>[]>(
      () => [
        {
          header: 'Public Key',
          id: 'public_key',
          accessorFn: (row) => (
            <ViewModal trigger={<a data-mp-event={mpEvents.viewDetails}>{row.public_key}</a>} data={row} />
          ),
          mantineTableHeadCellProps: {
            sx: {
              paddingLeft: '24px !important'
            }
          },
          mantineTableBodyCellProps: {
            sx: {
              paddingLeft: '24px !important'
            }
          }
        },
        {
          header: 'Private Key',
          id: 'private_key',
          minSize: 200,
          accessorFn: (row) => getPrivateKeyDisplay(row.digest)
        },
        {
          header: 'Description',
          accessorKey: 'description',
          minSize: 160
        },
        {
          header: 'Role',
          id: 'role',
          accessorFn: (row) => getAPIKeyRoleName(row.role)
        },
        {
          header: 'Actions',
          id: 'actions',
          Header: <Box px={8}>Actions</Box>,
          accessorFn: (row) => (
            <Menu withinPortal>
              <Menu.Target>
                <ActionIcon w={32} h={32} variant="subtle" data-mp-event="Start Project APIKey Actions">
                  <IconDotsHorizontal size={16} />
                </ActionIcon>
              </Menu.Target>
              <Menu.Dropdown>
                <Menu.Item
                  disabled={!actionsAccessible}
                  onClick={() => setEditKey(row)}
                  data-mp-event="Start Project APIKey Edit"
                >
                  Edit
                </Menu.Item>
                <Menu.Item
                  disabled={!actionsAccessible}
                  onClick={() => setDeleteKey(row)}
                  data-mp-event="Start Project APIKey Deletion"
                >
                  Delete
                </Menu.Item>
              </Menu.Dropdown>
            </Menu>
          )
        }
      ],
      [actionsAccessible]
    )

    return (
      <>
        {!!editKey && (
          <EditModal
            type={ScopeTypeConst.Project}
            visible={true}
            onFinish={refetch}
            data={editKey}
            onClose={() => {
              setEditKey(null)
            }}
          />
        )}
        {!!deleteKey && (
          <DeletionConfirm
            type={ScopeTypeConst.Project}
            visible={true}
            onConfirm={refetch}
            data={deleteKey!}
            onClose={() => {
              setDeleteKey(null)
            }}
          />
        )}
        <ProTable
          columns={columns}
          data={data?.items || []}
          loading={isLoading}
          emptyMessage="No API Keys available"
          manualPagination={true}
          pagination={
            data?.total
              ? {
                  total: Math.ceil(data.total / DEFAULT_PAGE_SIZE) || 0,
                  value: currentPage,
                  onChange: (page) => {
                    onPageChange(page)
                  }
                }
              : undefined
          }
        />
      </>
    )
  }
)

export const APIKeys = observer(() => {
  const {
    store: {
      tenantData: { id: orgId },
      userProfile: { projects }
    }
  } = useStores()

  const {
    data,
    isLoading,
    refetch: refetchOrgAPIKeys,
    pagination,
    isFetched
  } = useAPIKeyList({
    orgId
  })
  const enabledAPIKeysV2 = useAPIKeysV2()

  const [editKey, setEditKey] = useState<APIKeyItem | null>(null)
  const [deleteKey, setDeleteKey] = useState<APIKeyItem | null>(null)
  const [segmentType, setSegmentType] = useState<ScopeTypes>(ScopeTypeConst.Org)
  const [selectedProject, setSelectedProject] = useState(projects[0]?.id || '')

  const onSegmentTypeChange = useMemoizedFn((type: ScopeTypes) => {
    setSegmentType(type)
    pagination.onChange({ page: 1 })
    if (type === ScopeTypeConst.Project) {
      const projectExisted = projects.find((p) => p.id === selectedProject)

      if (!projectExisted) {
        setSelectedProject(projects[0]?.id || '')
      }
    }
  })

  const onProjectChange = (value: string) => {
    setSelectedProject(value)
    pagination.onChange({ page: 1 })
  }

  const refetchProjectAPIKeys = () => {
    queryClient.invalidateQueries(
      getListProjectOpenAPIKeysQueryKey(orgId, selectedProject, { page: pagination.page, per_page: 10 })
    )
  }

  const actionsAccessible = useAccessCheck('OrgAPIKeysAction')
  const columns = useMemo<MRT_ColumnDef<APIKeyItem>[]>(
    () => [
      {
        header: 'Public Key',
        id: 'public_key',
        accessorFn: (row) => (
          <ViewModal trigger={<a data-mp-event={mpEvents.viewDetails}>{row.public_key}</a>} data={row} />
        ),
        mantineTableHeadCellProps: {
          sx: {
            paddingLeft: '24px !important'
          }
        },
        mantineTableBodyCellProps: {
          sx: {
            paddingLeft: '24px !important'
          }
        }
      },
      {
        header: 'Private Key',
        id: 'private_key',
        minSize: 200,
        accessorFn: (row) => getPrivateKeyDisplay(row.digest)
      },
      {
        header: 'Description',
        accessorKey: 'description',
        minSize: 160
      },
      {
        header: 'Role',
        id: 'role',
        accessorFn: (row) => getAPIKeyRoleName(row.role)
      },
      {
        header: 'Actions',
        id: 'actions',
        Header: <Box px={8}>Actions</Box>,
        accessorFn: (row) => (
          <Menu withinPortal>
            <Menu.Target>
              <ActionIcon w={32} h={32} variant="subtle" data-mp-event="Project Management Actions Clicked">
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>
            <Menu.Dropdown>
              <Menu.Item
                disabled={!actionsAccessible}
                onClick={() => {
                  setEditKey(row)
                }}
                data-mp-event={mpEvents.startEdit}
              >
                Edit
              </Menu.Item>
              <Menu.Item
                disabled={!actionsAccessible}
                onClick={() => {
                  setDeleteKey(row)
                }}
                data-mp-event={mpEvents.startDeletion}
              >
                Delete
              </Menu.Item>
            </Menu.Dropdown>
          </Menu>
        )
      }
    ],
    [actionsAccessible]
  )

  return (
    <PageShell
      title="API Keys"
      headerProps={{
        sticky: true,
        rightSection: (
          <>
            {segmentType === ScopeTypeConst.Org && (
              <AccessDeniedHoverHint id="OrgAPIKeysAction">
                {({ accessible }) => (
                  <CreationModal
                    trigger={
                      <Button
                        size="sm"
                        disabled={!accessible}
                        data-mp-event={mpEvents.startCreation}
                        data-testid="create-api-key"
                      >
                        Create API Key
                      </Button>
                    }
                    onFinish={refetchOrgAPIKeys}
                  />
                )}
              </AccessDeniedHoverHint>
            )}
            {segmentType === ScopeTypeConst.Project && (
              <AccessDeniedHoverHint id="OrgAPIKeysAction">
                {({ accessible }) => (
                  <ProjectAPIKeyCreationModal
                    trigger={
                      <Button size="sm" disabled={!accessible} data-mp-event={'Start Project APIKey Creation'}>
                        Create Project API Key
                      </Button>
                    }
                    onFinish={refetchProjectAPIKeys}
                    projectName={projects.find((p) => p.id === selectedProject)?.name || ''}
                    projectId={selectedProject}
                  />
                )}
              </AccessDeniedHoverHint>
            )}
          </>
        )
      }}
    >
      {enabledAPIKeysV2 && (
        <Group>
          <SegmentedControl
            value={segmentType}
            onChange={onSegmentTypeChange}
            data={[
              { label: 'By Organization', value: ScopeTypeConst.Org },
              { label: 'By Project', value: ScopeTypeConst.Project }
            ]}
          />
          {segmentType === ScopeTypeConst.Project && (
            <Select
              data={projects.map(({ id, name }) => ({ value: id, label: name }))}
              value={selectedProject}
              onChange={onProjectChange}
            />
          )}
        </Group>
      )}
      <Alert my={24}>
        <Typography
          variant="action-md"
          fw={400}
          component="a"
          target="_blank"
          href="https://docs.pingcap.com/api/tidb-cloud-api-overview/"
          rel="noreferrer"
          data-mp-event={mpEvents.learnMore}
        >
          TiDB Cloud API (v1beta1)
        </Typography>{' '}
        supports role-based access control (RBAC) for API key management at both the organization and project levels.
      </Alert>
      {segmentType === ScopeTypeConst.Org && (
        <ProTable
          columns={columns}
          data={data.items}
          loading={isLoading}
          emptyMessage="No API Keys available"
          manualPagination={true}
          pagination={
            data?.total
              ? {
                  total: Math.ceil(data.total / pagination.pageSize) || 0,
                  value: pagination.page,
                  onChange: (page) => {
                    pagination.onChange({ page })
                  }
                }
              : undefined
          }
        />
      )}
      {segmentType === ScopeTypeConst.Project && (
        <ProjectAPIKeys
          projectId={selectedProject}
          orgId={orgId}
          currentPage={pagination.page}
          onPageChange={(page) => {
            pagination.onChange({ page })
          }}
        />
      )}
      {!!editKey && (
        <EditModal
          type={ScopeTypeConst.Org}
          visible={true}
          onFinish={refetchOrgAPIKeys}
          data={editKey}
          disabled={!enabledAPIKeysV2}
          onClose={() => {
            setEditKey(null)
          }}
        />
      )}
      {!!deleteKey && (
        <DeletionConfirm
          type={segmentType}
          visible={true}
          onConfirm={refetchOrgAPIKeys}
          data={deleteKey!}
          onClose={() => {
            setDeleteKey(null)
          }}
        />
      )}
      {isFetched && <HeroComponent />}
    </PageShell>
  )
})
