import { ActionIcon, Box, Button, Group, HoverCard, Menu, notifier, Select, TextInput } from '@tidbcloud/uikit'
import { MRT_ColumnDef, MRT_SortingState, ProTable } from '@tidbcloud/uikit/biz'
import { useDebouncedCallback } from '@tidbcloud/uikit/hooks'
import { IconDotsHorizontal, IconInfoCircle, IconSearchSm, IconXClose } from '@tidbcloud/uikit/icons'
import { observer } from 'mobx-react'
import { useState } from 'react'

import { HeroComponent } from 'dbaas/components/Measurement'
import TimeComponent from 'dbaas/components/TimeComponent'
import { AccessDeniedHoverHint, useAccessCheck } from 'dbaas/contexts/access-control'
import { PageShell } from 'dbaas/layouts/v5/page'
import { inviteUserToOrg, useListConsoleUsers } from 'dbaas/services/account'
import {
  CentralConsoleUser,
  CentralListConsoleUsersSupportScopeType,
  CentralUser
} from 'dbaas/services/account/interface'
import { useTidbServiceListTidbs } from 'dbaas/services/api-clients/v2025/tidb-management/v1beta2'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import { UserDeletionModal } from './DeletionModal'
import { UserDetail } from './Detail'
import { UserInvitation } from './invite-user'
// import { RolesSelectOptions } from './shared/roles'
import { RolesView } from './shared/roles/RolesView'
import { StatusTag } from './shared/status'

export const Users = observer(() => {
  const {
    store: {
      lastVisitLocation: { orgId, projectId },
      userProfile: { email, projects }
    }
  } = useStores()

  const orgLoginTimeAccessible = useAccessCheck('OrgUsersLoginTimeGate')
  const orgUsersActionAccessible = useAccessCheck('OrgUsersV2Action')

  const [userInvitationOpened, setUserInvitationOpened] = useState(false)
  const [userEditData, setUserEditData] = useState<CentralConsoleUser | undefined>(undefined)
  const [userDeletionData, setUserDeletionData] = useState<CentralConsoleUser | undefined>(undefined)
  const [userDetailIndex, setUserDetailIndex] = useState<number | undefined>(undefined)

  const [pagination, setPagination] = useState<{
    pageIndex: number
    pageSize: number
  }>({
    pageIndex: 0,
    pageSize: 10
  })
  const [orgSorting, setOrgSorting] = useState<MRT_SortingState>([])
  const [params, setParams] = useState<{
    status?: string
    email?: string
    roles?: string[]
    projectId?: string
    clusterId?: string
  }>({})

  const [debouncedFilterParams, setDebouncedFilterParams] = useState<{
    status?: string
    email?: string
    roles?: string[]
    projectId?: string
    clusterId?: string
  }>({})

  const handleFilter = useDebouncedCallback((newParams: typeof params) => {
    setDebouncedFilterParams(newParams)
    setPagination((prev) => ({ ...prev, pageIndex: 0 }))
  }, 500)

  const { data, isLoading, isFetched, refetch } = useListConsoleUsers(
    orgId,
    {
      page: pagination.pageIndex + 1,
      per_page: pagination.pageSize,
      email: debouncedFilterParams.email ? encodeURIComponent(debouncedFilterParams.email) : undefined,
      sort_by: orgSorting[0]?.id ?? undefined,
      order: orgSorting[0] ? (orgSorting[0].desc ? 'desc' : 'asc') : undefined,
      statuses: debouncedFilterParams.status ? [debouncedFilterParams.status] : undefined,
      roles: debouncedFilterParams.roles ? debouncedFilterParams.roles : undefined,
      scope_type: debouncedFilterParams.clusterId
        ? CentralListConsoleUsersSupportScopeType.TIDB
        : debouncedFilterParams.projectId
          ? CentralListConsoleUsersSupportScopeType.PROJECT
          : CentralListConsoleUsersSupportScopeType.ORG,
      project_id: debouncedFilterParams.projectId ? debouncedFilterParams.projectId : undefined,
      cluster_id: debouncedFilterParams.clusterId ? debouncedFilterParams.clusterId : undefined
    },
    {
      query: {
        enabled: true
      }
    }
  )

  const { data: tidbData } = useTidbServiceListTidbs({
    orgId,
    projectId,
    pageSize: 100
  })

  const projectOptions = projects.map((project) => ({ label: project.name, value: project.id }))
  const instanceOptions = tidbData?.tidbs?.map((tidb) => ({ label: tidb.displayName || '', value: tidb.tidbId || '' }))
  const isProjectFilterDisabled = params.clusterId ? true : false
  const isInstanceFilterDisabled = params.projectId ? true : false

  const columns: MRT_ColumnDef<CentralConsoleUser>[] = [
    {
      header: 'Account',
      accessorKey: 'email',
      Cell: ({ row: { original: originalRow, index: rowIndex } }) => {
        return (
          <Box
            sx={(theme) => ({
              cursor: 'pointer',
              color: theme.colors.peacock[7]
            })}
            onClick={() => {
              setUserDetailIndex(rowIndex)
            }}
          >
            {originalRow.email}
          </Box>
        )
      },
      maxSize: 240,
      mantineTableHeadCellProps: {
        pl: '24px !important'
      },
      mantineTableBodyCellProps: {
        pl: '24px !important'
      }
    },
    {
      header: 'Role',
      id: 'role',
      minSize: 240,
      Cell: ({ row }) => (
        <RolesView user={row.original} projectOptions={projectOptions} instanceOptions={instanceOptions || []} />
      )
    },
    {
      header: 'Status',
      accessorKey: 'status',
      maxSize: 100,
      accessorFn: (row) => <StatusTag status={row.status || ''} />
    },
    {
      header: 'Invite Time',
      id: 'invite_time',
      maxSize: 150,
      accessorFn: (row) => <TimeComponent time={row.invite_time || ''} />
    },
    {
      header: 'Last Login Time',
      id: 'login_time',
      maxSize: 150,
      mantineTableHeadCellProps: {
        display: orgLoginTimeAccessible ? undefined : 'none'
      },
      mantineTableBodyCellProps: {
        display: orgLoginTimeAccessible ? undefined : 'none'
      },
      accessorFn(originalRow) {
        if (!originalRow.login_time) {
          return originalRow.status === 'ACTIVE' ? '-' : 'Has not logged in yet'
        }
        return <TimeComponent time={originalRow.login_time} />
      }
    },
    {
      header: '',
      id: 'action',
      size: 40,
      accessorFn: (row) => {
        const showResend = row.status !== 'ACTIVE'
        const showDelete = row.email !== email

        return (
          <Menu withinPortal withArrow position="bottom-end">
            <Menu.Target>
              <ActionIcon w={32} h={32} variant="subtle" data-mp-event="User Management Actions Clicked">
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>
            <Menu.Dropdown maw={164}>
              {showResend && (
                <Menu.Item
                  disabled={!orgUsersActionAccessible}
                  onClick={async () => {
                    eventTracking('User Management Resend Button Clicked', {})
                    try {
                      await inviteUserToOrg(orgId, {
                        email: row.email || '',
                        rbac_role: row.org_role?.rbac_role || ''
                      })
                      notifier.success('Invitation sent successfully!', { autoClose: 3500 })
                    } catch (e) {
                      notifier.error(getErrorMessage(e), { autoClose: 3500 })
                    }
                    refetch()
                  }}
                >
                  Resend Invitation
                </Menu.Item>
              )}
              <Menu.Item
                disabled={!orgUsersActionAccessible}
                onClick={() => {
                  eventTracking('User Management Edit Button Clicked', {})
                  setUserEditData(row)
                }}
              >
                Edit Role
              </Menu.Item>
              {showDelete && (
                <Menu.Item
                  disabled={!orgUsersActionAccessible}
                  onClick={() => {
                    eventTracking('User Management Delete Button Clicked')
                    setUserDeletionData(row)
                  }}
                  c="red.7"
                >
                  Delete
                </Menu.Item>
              )}
            </Menu.Dropdown>
          </Menu>
        )
      },
      enableSorting: false
    }
  ]

  return userInvitationOpened || userEditData ? (
    <UserInvitation
      onClose={() => {
        setUserInvitationOpened(false)
        setUserEditData(undefined)
        setUserDetailIndex(undefined)
      }}
      onFinish={refetch}
      user={userEditData}
    />
  ) : (
    <PageShell
      title="Users"
      headerProps={{
        sticky: true,
        rightSection: (
          <AccessDeniedHoverHint id="OrgUsersV2Action">
            {({ accessible }) => (
              <Button
                size="sm"
                disabled={!accessible}
                onClick={() => setUserInvitationOpened(true)}
                data-mp-event="User Management Invite Button Clicked"
              >
                Invite User
              </Button>
            )}
          </AccessDeniedHoverHint>
        )
      }}
    >
      <Group>
        <TextInput
          w={240}
          placeholder="Search User"
          value={params.email}
          leftSection={<IconSearchSm size={14} sx={{ cursor: 'pointer' }} />}
          rightSection={
            !!params.email && (
              <IconXClose
                size={14}
                sx={{ cursor: 'pointer' }}
                onClick={() => {
                  const newParams = { ...params, email: '' }
                  setParams(newParams)
                  handleFilter(newParams)
                }}
              />
            )
          }
          onChange={(event) => {
            const newParams = { ...params, email: event.currentTarget.value }
            setParams(newParams)
            handleFilter(newParams)
          }}
        />
        <HoverCard disabled={!isProjectFilterDisabled}>
          <HoverCard.Target>
            <Box>
              <Select
                placeholder="Project"
                disabled={isProjectFilterDisabled}
                rightSection={isProjectFilterDisabled ? <IconInfoCircle size={16} /> : undefined}
                searchable
                data={projectOptions}
                clearable
                value={params.projectId}
                onChange={(value) => {
                  const newParams = { ...params, projectId: value || '' }
                  setParams(newParams)
                  handleFilter(newParams)
                }}
              ></Select>
            </Box>
          </HoverCard.Target>
          <HoverCard.Dropdown>Only one context (Project or Instance) can be filtered at a time.</HoverCard.Dropdown>
        </HoverCard>
        <HoverCard disabled={!isInstanceFilterDisabled}>
          <HoverCard.Target>
            <Box>
              <Select
                data={instanceOptions}
                placeholder="Instances"
                searchable
                clearable
                value={params.clusterId}
                disabled={isInstanceFilterDisabled}
                rightSection={isInstanceFilterDisabled ? <IconInfoCircle size={16} /> : undefined}
                onChange={(value) => {
                  const newParams = { ...params, clusterId: value || '' }
                  setParams(newParams)
                  handleFilter(newParams)
                }}
              ></Select>
            </Box>
          </HoverCard.Target>
          <HoverCard.Dropdown>Only one context (Project or Instance) can be filtered at a time.</HoverCard.Dropdown>
        </HoverCard>
        {/* TODO: remove this after multiple roles are supported */}
        {/* <ProMultiSelect
          data={RolesSelectOptions}
          placeholder="Roles"
          width={260}
          clearable={true}
          value={params.roles}
          searchable={true}
          onChange={(value) => {
            const newParams = { ...params, roles: value || [] }
            setParams(newParams)
            handleFilter(newParams)
          }}
        /> */}
        {/* TODO: ask the backend to provide the `status` enum in the Swagger spec */}
        <Select
          data={[
            { label: 'Active', value: 'ACTIVE' },
            { label: 'Pending', value: 'PENDING' }
          ]}
          placeholder="Status"
          clearable={true}
          value={params.status}
          onChange={(value) => {
            const newParams = { ...params, status: value || '' }
            setParams(newParams)
            handleFilter(newParams)
          }}
        />
      </Group>
      <Box mt="xl" mb={8}>
        <ProTable
          columns={columns}
          data={data?.items || []}
          loading={isLoading}
          enableSorting={true}
          emptyMessage="No Data"
          state={{
            sorting: orgSorting,
            pagination,
            columnVisibility: {
              login_time: orgLoginTimeAccessible
            }
          }}
          manualSorting={true}
          onSortingChange={(data) => {
            setPagination({ ...pagination, pageIndex: 0 })
            setOrgSorting(data)
          }}
          manualPagination={true}
          onPaginationChange={setPagination}
          rowCount={data?.total || 0}
          pagination={{
            showRowsPerPage: true,
            showTotal: true
          }}
        />
      </Box>
      {userDeletionData && (
        <UserDeletionModal
          user={userDeletionData}
          opened={true}
          onClose={() => setUserDeletionData(undefined)}
          onFinish={() => {
            refetch()
          }}
        />
      )}

      <UserDetail
        opened={userDetailIndex !== undefined}
        user={userDetailIndex !== undefined ? data?.items[userDetailIndex] : undefined}
        onClose={() => {
          setUserDetailIndex(undefined)
          refetch()
        }}
        disableNext={userDetailIndex === (data?.items?.length || 0) - 1}
        disablePrev={userDetailIndex === 0}
        onNext={() => {
          setUserDetailIndex(userDetailIndex !== undefined ? userDetailIndex + 1 : 0)
        }}
        onEdit={(user) => {
          setUserEditData(user as CentralUser)
        }}
        onPrev={() => {
          setUserDetailIndex(userDetailIndex !== undefined ? userDetailIndex - 1 : 0)
        }}
      />
      {isFetched && <HeroComponent />}
    </PageShell>
  )
})

export default Users
