import {
  ActionIcon,
  Box,
  Center,
  Group,
  Loader,
  Menu,
  SegmentedControl,
  Select,
  Typography,
  notifier,
  openModal
} 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 { ModalCodeTitle } from 'dbaas/components'
import { AccessGuard, RBACRoleUINames } from 'dbaas/contexts/access-control'
import { PageShell } from 'dbaas/layouts/v5/page'
import { useListScimGroups, useUpdateScimGroupRole } from 'dbaas/services/account'
import { CentralScimGroup, CentralScimGroupMember } from 'dbaas/services/account/interface'
import { getErrorMessage } from 'dbaas/services/errorCodes'
import useStores from 'dbaas/stores/useStores'
import { eventTracking } from 'dbaas/utils/tracking'

import { orgRoleOptions, projectRoleOptions } from '../constant'
import { ScopeTypeConst } from '../UserAccess/helpers'

interface EditableProjectRoleCellProps {
  data: CentralScimGroup
  orgId: string
  projectId: string
  onChange?: () => void
}

const EditableGroupProjectRoleCell = observer(({ data, orgId, projectId, onChange }: EditableProjectRoleCellProps) => {
  const [value, setValue] = useState<string | undefined>(
    data.project_roles?.find((project) => project.project_id === projectId)?.project_role || ''
  )

  const roleMutation = useUpdateScimGroupRole({
    mutation: {
      onSuccess: (_response, { data: { project_role: role } }) => {
        setValue(role)
        onChange?.()
      },
      onError: (error) => {
        const errMsg = getErrorMessage(error)
        notifier.error(errMsg)
      }
    }
  })

  const handleChange = async (role: string) => {
    return roleMutation.mutateAsync({
      orgId,
      id: data.id || '',
      data: {
        group_id: data.group_id,
        project_role: role,
        project_ids: [projectId]
      }
    })
  }

  return (
    <Select
      variant="unstyled"
      placeholder="-"
      data={projectRoleOptions}
      value={value}
      onChange={handleChange}
      required
      withAsterisk={false}
      disabled={roleMutation.isLoading}
      rightSection={roleMutation.isLoading ? <Loader size={14} /> : undefined}
      w={262}
      styles={() => ({ input: { minHeight: 32, height: 32, backgroundColor: 'transparent', border: 'none' } })}
    />
  )
})

interface EditableGroupCellProps {
  data: CentralScimGroup
  orgId: string
  onChange?: () => void
}

export const EditableGroupOrgCell = ({ data, orgId, onChange }: EditableGroupCellProps) => {
  const [value, setValue] = useState(data.org_role || '')

  const roleMutation = useUpdateScimGroupRole({
    mutation: {
      onSuccess: (_response, { data: { org_role: role } }) => {
        setValue(role || '')
        onChange?.()
      },
      onError: (error) => {
        const errMsg = getErrorMessage(error)
        notifier.error(errMsg)
      }
    }
  })

  const handleChange = async (role: string) => {
    return roleMutation.mutateAsync({
      orgId,
      id: data.id || '',
      data: {
        group_id: data.group_id,
        org_role: role
      }
    })
  }

  return (
    <Select
      variant="unstyled"
      placeholder="-"
      data={orgRoleOptions}
      value={value}
      onChange={handleChange}
      required
      withAsterisk={false}
      disabled={roleMutation.isLoading}
      rightSection={roleMutation.isLoading ? <Loader size={14} /> : undefined}
      w={288}
      styles={() => ({ input: { minHeight: 32, height: 32, backgroundColor: 'transparent', border: 'none' } })}
    />
  )
}

export const openMembersModal = (data: CentralScimGroup) => {
  const columns: MRT_ColumnDef<CentralScimGroupMember>[] = [
    {
      header: 'Email',
      accessorKey: 'display'
    }
  ]

  return openModal({
    title: (
      <>
        Members in Group <ModalCodeTitle>{data.group_name}</ModalCodeTitle>
      </>
    ),
    centered: true,
    size: 600,
    children: (
      <ProTable
        columns={columns}
        data={data.members || []}
        emptyMessage="No Data"
        enableStickyHeader
        mantinePaperProps={{
          sx: {
            marginTop: 16
          }
        }}
        mantineTableContainerProps={{ sx: { maxHeight: '200px', overflow: 'auto' } }}
      ></ProTable>
    )
  })
}

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

  const pageSize = 10
  const [currentPage, setCurrentPage] = useState(1)

  const [segmentType, setSegmentType] = useState<string>(ScopeTypeConst.Org)
  const onSegmentTypeChange = useMemoizedFn((type: string) => {
    setSegmentType(type)
    setCurrentPage(1)
  })
  const [selectedProject, setSelectedProject] = useState(projects[0]?.id || '')
  const { data, refetch, isLoading, isFetched } = useListScimGroups(orgId, { page: currentPage, per_page: pageSize })

  const onProjectChange = (value: string) => {
    setSelectedProject(value)
    setCurrentPage(1)
  }

  const columns = useMemo<MRT_ColumnDef<CentralScimGroup>[]>(
    () => [
      {
        header: 'Group',
        accessorKey: 'group_name',
        id: 'group_id',
        mantineTableHeadCellProps: {
          sx: {
            paddingLeft: '24px !important'
          }
        },
        mantineTableBodyCellProps: {
          sx: {
            paddingLeft: '24px !important'
          }
        },
        size: 150
      },
      {
        header: 'Organization Role',
        id: 'org_role',
        accessorFn(originalRow) {
          return (
            <AccessGuard
              key={`${originalRow.group_id}-${originalRow.org_role}`}
              id="OrgGroupUserAction"
              fallback={RBACRoleUINames[originalRow.org_role || ''] || '-'}
            >
              <EditableGroupOrgCell data={originalRow} orgId={orgId} onChange={refetch} />
            </AccessGuard>
          )
        }
      },
      {
        header: 'Project Role',
        id: 'project_role',
        size: 200,
        accessorFn(originalRow) {
          const role =
            originalRow.project_roles?.find((project) => project.project_id === selectedProject)?.project_role || ''
          return (
            <AccessGuard
              id="ProjectGroupUserAction"
              scopeProps={{ projectId: selectedProject }}
              fallback={RBACRoleUINames[role] || '-'}
              key={`${originalRow.group_id}-${selectedProject}`}
            >
              <EditableGroupProjectRoleCell
                data={originalRow}
                orgId={orgId}
                projectId={selectedProject}
                onChange={refetch}
              />
            </AccessGuard>
          )
        }
      },
      {
        header: 'Action',
        id: 'action',
        size: 10,
        Header: <Box px={8}>Actions</Box>,
        accessorFn: (row) => (
          <Menu withinPortal>
            <Menu.Target>
              <ActionIcon w={32} h={32} variant="subtle" data-mp-event="">
                <IconDotsHorizontal size={16} />
              </ActionIcon>
            </Menu.Target>
            <Menu.Dropdown>
              <Menu.Item
                onClick={() => {
                  eventTracking('View Group Members')
                  openMembersModal(row)
                }}
              >
                View
              </Menu.Item>
            </Menu.Dropdown>
          </Menu>
        )
      }
    ],
    [orgId, selectedProject, refetch]
  )

  if (!isFetched) {
    return (
      <Center mt="xl">
        <Loader mih={200} />
      </Center>
    )
  }

  return (
    <PageShell
      title="Groups"
      headerProps={{
        sticky: true,
        bg: 'carbon.1'
      }}
      bodyProps={{ pt: 0 }}
    >
      {!!data?.group?.length ? (
        <>
          <Group>
            <SegmentedControl
              value={segmentType}
              onChange={onSegmentTypeChange}
              data={[
                { label: 'By Organization', value: ScopeTypeConst.Org },
                { label: 'By Project', value: ScopeTypeConst.Project }
              ]}
              py={5}
            />
            {segmentType === ScopeTypeConst.Project && !!projects.length && (
              <Select
                data={projects.map(({ id, name }) => ({ value: id, label: name }))}
                value={selectedProject}
                onChange={onProjectChange}
              />
            )}
          </Group>

          <ProTable
            key={segmentType + selectedProject}
            loading={isLoading}
            mantinePaperProps={{
              mt: 24
            }}
            columns={columns}
            data={data?.group || []}
            emptyMessage="No Data"
            state={{
              columnVisibility: {
                org_role: segmentType === ScopeTypeConst.Org,
                project_role: segmentType === ScopeTypeConst.Project
              }
            }}
            manualPagination={true}
            pagination={
              data?.total
                ? {
                    total: Math.ceil((data?.total || 0) / pageSize) || 0,
                    value: currentPage,
                    onChange: setCurrentPage
                  }
                : void 0
            }
          ></ProTable>
        </>
      ) : (
        <Center sx={{ flexDirection: 'column' }} mih={300}>
          <Typography variant="title-lg">No Groups available.</Typography>
          <Typography variant="body-lg">Please push groups from your IdP and refresh the page.</Typography>
        </Center>
      )}
    </PageShell>
  )
})
