import { PlusOutlined, MinusOutlined } from '@ant-design/icons'
import {
  Button,
  Card,
  Descriptions,
  Divider,
  Modal,
  Space,
  Tag,
  Table
} from 'antd'
import { ColumnsType } from 'antd/lib/table'
import Title from 'antd/lib/typography/Title'
import React, { useCallback, useEffect, useMemo, useState } from 'react'
import { useHistory, useParams } from 'react-router-dom'

import {
  userServiceDeleteGroup,
  userServiceGetGroup,
  userServiceListUsers,
  userServiceMapUsersToGroup,
  userServiceUnmapUsersFromGroup
} from 'apiClient/services/core-server'
import {
  V1RoleBindingTargetType,
  V1User,
  V1UserGroup
} from 'apiClient/services/core-server/interface'
import ModalForm from 'components/ModalForm'
import SearchBar from 'components/SearchBar'
import { ListToolBar, useTable } from 'components/Table'
import {
  formatUserGroupSource,
  showErrorModal,
  toListDataResponse
} from 'pages/IAM/utils'
import { toLocal } from 'utils/time'

import ShowPermissions from '../../Role/Policy/Forms/ShowPermissions'
import ShowBindingRoles from '../../Role/Role/Forms/ShowBindingRoles'

import AddUserForm, { AddUserFormType } from './Forms/AddUserForm'
import DeleteUserGroupForm, {
  DeleteUserGroupFormType
} from './Forms/DeleteGroupForm'

export default function UserGroupDetail() {
  const { user_group } = useParams<{
    user_group: string
  }>()
  const [userGroupInfo, setUserGroupInfo] = useState<V1UserGroup>()
  const history = useHistory()
  const [deleteGroup, setDeleteGroup] = useState(false)
  const [activeTabKey, setActiveTabKey] = useState<string>('users')

  useEffect(() => {
    fetch()
  }, [])

  async function fetch() {
    try {
      const data = (await userServiceGetGroup(user_group)).data
      setUserGroupInfo(data.group)
    } catch (e) {
      console.error(e)
    }
  }

  const renderDeleteFormFields = useCallback(() => {
    return <DeleteUserGroupForm />
  }, [deleteGroup])

  const handleDelete = useCallback(async (payload: DeleteUserGroupFormType) => {
    const req = {
      ...payload
    }
    try {
      await userServiceDeleteGroup(user_group, req)
      Modal.success({
        title: 'Info',
        content: (
          <div>
            <p>{`User Group ${user_group} has been deleted.`}</p>
          </div>
        ),
        onOk() {
          history.push('/iam/entity')
        }
      })
    } catch (error) {
      showErrorModal(error)
    }
  }, [])

  const handleCancelDelete = useCallback(() => {
    setDeleteGroup(false)
  }, [])

  const tabList = [
    {
      key: 'users',
      tab: 'Users'
    },
    {
      key: 'roles',
      tab: 'Roles'
    },
    {
      key: 'permissions',
      tab: 'Permissions'
    }
  ]
  const contentList: Record<string, React.ReactNode> = {
    users: <ShowUsers group_name={user_group} />,
    roles: (
      <ShowBindingRoles
        target={{
          name: user_group,
          type: V1RoleBindingTargetType.ROLE_BINDING_TARGET_TYPE_USER_GROUP
        }}
      />
    ),
    permissions: (
      <ShowPermissions
        target={{
          name: user_group,
          type: V1RoleBindingTargetType.ROLE_BINDING_TARGET_TYPE_USER_GROUP
        }}
      />
    )
  }

  return (
    <>
      <div>
        <Card
          title={<Title level={4}>{`User Group '${user_group}'`}</Title>}
          extra={
            <Space>
              <Button
                type="ghost"
                onClick={() => {
                  setDeleteGroup(true)
                }}
              >
                Delete
              </Button>
            </Space>
          }
        >
          <Descriptions>
            <Descriptions.Item label="Name">
              {userGroupInfo?.base?.name}
            </Descriptions.Item>
            <Descriptions.Item label="Parent Group">
              {userGroupInfo?.base?.parentName ? (
                <a
                  href={`/iam/entity/usergroups/${userGroupInfo.base.parentName}`}
                >
                  {userGroupInfo.base.parentName}
                </a>
              ) : (
                '-'
              )}
            </Descriptions.Item>
            <Descriptions.Item label="Source">
              {formatUserGroupSource(userGroupInfo?.base?.source)}
            </Descriptions.Item>
            <Descriptions.Item label="Created At">
              {toLocal(userGroupInfo?.base?.createdAt)}
            </Descriptions.Item>
            <Descriptions.Item label="Description">
              {userGroupInfo?.base?.description}
            </Descriptions.Item>
            <Descriptions.Item label="Tags" span={3}>
              {userGroupInfo?.tags?.length ? (
                <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
                  {userGroupInfo.tags.map((tag) => (
                    <Tag
                      key={`${tag.key}-${tag.value}`}
                      style={{
                        marginRight: 0,
                        marginBottom: 0,
                        maxWidth: '100%',
                        whiteSpace: 'normal'
                      }}
                    >
                      <span style={{ overflowWrap: 'anywhere' }}>
                        {tag.key ?? '-'}: {tag.value ?? '-'}
                      </span>
                    </Tag>
                  ))}
                </div>
              ) : (
                '-'
              )}
            </Descriptions.Item>
          </Descriptions>

          <Divider />
          <Card
            tabList={tabList}
            tabProps={{ size: 'middle' }}
            bordered={false}
            activeTabKey={activeTabKey}
            onTabChange={(key) => {
              setActiveTabKey(key)
            }}
          >
            {contentList[activeTabKey]}
          </Card>
        </Card>

        <ModalForm<DeleteUserGroupFormType>
          visible={!!deleteGroup}
          name="deleteGroup"
          title={`Delete User Group ${user_group}`}
          getFields={renderDeleteFormFields}
          onSubmit={handleDelete}
          onCancel={handleCancelDelete}
          width={1000}
        />
      </div>
    </>
  )
}

function ShowUsers({ group_name }: { group_name: string }) {
  const [addUser, setAddUser] = useState(false)
  const [selectedRowKeys, setSelectedRowKeys] = useState<React.Key[]>([])
  const [userQueryParams, setUserQueryParams] = useState<{
    email?: string
  }>({
    email: undefined
  })

  const fetchUsers = (params?: Partial<PageInfo>) => {
    return userServiceListUsers({
      ...userQueryParams,
      groupIs: group_name,
      page: params?.page,
      perPage: params?.pageSize
    }).then((response) => toListDataResponse(response, (data) => data.users))
  }

  const { dataSource, loading, reload, paginationProps, onTableChange } =
    useTable<ListData<V1User>>(fetchUsers, [], {
      pagination: true
    })

  const columns: ColumnsType<V1User> = [
    {
      title: 'Email',
      render: (_: any, record) => {
        return record.email
      }
    },
    {
      title: 'Name',
      render: (_: any, record) => {
        return record.larkUserName
      }
    },
    {
      title: 'Department',
      render: (_: any, record) => {
        return record.larkDepartmentName
      }
    }
  ]

  const onSearch = (query: { email?: string }) => {
    let newQuery: { [key: string]: any } = { ...query }
    newQuery.page = 1
    setUserQueryParams(newQuery)
    return reload()
  }

  const handleRemove = useCallback(async () => {
    Modal.info({
      title: 'Info',
      content: (
        <div>
          <p>Are you sure to remove {selectedRowKeys.join(', ')}?</p>
        </div>
      ),
      async onOk() {
        const req = {
          emails: selectedRowKeys.map((v) => {
            return v.toString()
          })
        }
        try {
          await userServiceUnmapUsersFromGroup(group_name, req)
          Modal.success({
            title: 'Info',
            content: (
              <div>
                <p>
                  {selectedRowKeys.join(', ')} has been removed from group{' '}
                  {group_name}
                </p>
              </div>
            ),
            onOk() {}
          })
          setSelectedRowKeys([])
          reload()
        } catch (error) {
          showErrorModal(error)
        }
      }
    })
  }, [reload])

  const handleAdd = useCallback(
    async (payload: AddUserFormType) => {
      try {
        await userServiceMapUsersToGroup(group_name, {
          emails: payload.emails
        })
        Modal.success({
          title: 'Info',
          content: (
            <div>
              <p>
                Users {payload.emails.join(', ')} have been successfully added.
              </p>
            </div>
          ),
          onOk() {}
        })
        setAddUser(false)
        reload()
      } catch (error) {
        showErrorModal(error)
      }
    },
    [reload]
  )

  const renderAddFormFields = useCallback(() => {
    return <AddUserForm />
  }, [addUser])

  const actions = useMemo(
    () => [
      <SearchBar
        defaultValue={userQueryParams}
        options={['email']}
        labels={['Email']}
        fetcher={onSearch}
      />,
      <Button
        type="primary"
        onClick={() => {
          setAddUser(true)
        }}
        icon={<PlusOutlined />}
      >
        Add
      </Button>,
      <Button type="primary" onClick={handleRemove} icon={<MinusOutlined />}>
        Remove
      </Button>
    ],
    [userQueryParams, selectedRowKeys]
  )

  const onSelectChange = (newSelectedRowKeys: React.Key[]) => {
    setSelectedRowKeys(newSelectedRowKeys)
  }

  const rowSelection = {
    selectedRowKeys,
    onChange: onSelectChange
  }

  return (
    <div>
      <Title level={4}>Users</Title>
      <ListToolBar actions={actions} reload={reload}></ListToolBar>
      <Table<V1User>
        rowKey="email"
        columns={columns}
        dataSource={dataSource}
        loading={loading}
        pagination={{ ...paginationProps }}
        size="small"
        onChange={onTableChange}
        rowSelection={rowSelection}
      ></Table>

      <ModalForm<AddUserFormType>
        visible={!!addUser}
        name="addUser"
        title={`Map a User to Group ${group_name}`}
        getFields={renderAddFormFields}
        onSubmit={handleAdd}
        onCancel={() => {
          setAddUser(false)
        }}
        width={1000}
      />
    </div>
  )
}
