import { CodeBlock } from '@tidbcloud/uikit/biz'
import {
  Alert,
  Button,
  Card,
  Checkbox,
  Descriptions,
  Empty,
  Input,
  Modal,
  Space,
  Table,
  Tag,
  Typography,
  message
} from 'antd'
import { ColumnsType } from 'antd/lib/table'
import { useCallback, useMemo, useState } from 'react'
import useProfileContext from 'useProfileContext'

import {
  userServiceDeleteAPIToken,
  userServiceGenerateAPIToken,
  userServiceListAPITokens,
  userServiceUpsertAPITokenIPAccessList,
  useUserServiceGetAPITokenIPAccessList
} from 'apiClient/services/core-server'
import {
  UserServiceListAPITokensStatusIs,
  V1APIToken,
  V1APITokenIPRule,
  V1APITokenPrivilege,
  V1APITokenStatus
} from 'apiClient/services/core-server/interface'
import { ListToolBar, useTable } from 'components/Table'
import { toListDataResponse } from 'pages/IAM/utils'
import { toLocal } from 'utils/time'

import CreateAPITokenForm, {
  CreateAPITokenFormType
} from './Forms/CreateAPIToken'
import EditIPAccessListForm, {
  EditIPAccessListFormType
} from './Forms/EditIPAccessList'

export default function Profile() {
  const {
    profile: { operatorName, userEmail, roles }
  } = useProfileContext()
  const roleNames = Object.keys(roles ?? {})

  const [createTokenVisible, setCreateTokenVisible] = useState(false)
  const [createdTokenVisible, setCreatedTokenVisible] = useState(false)
  const [createdToken, setCreatedToken] = useState('')
  const [editIPAccessListVisible, setEditIPAccessListVisible] = useState(false)
  const [showInactiveTokens, setShowInactiveTokens] = useState(false)
  const [nameLike, setNameLike] = useState('')
  const [ipAccessListFormInitialValues, setIPAccessListFormInitialValues] =
    useState<EditIPAccessListFormType>({
      allow_all: false,
      rules: [{ cidr: '', description: '' }]
    })

  const {
    data: ipAccessListResp,
    isLoading: ipAccessListLoading,
    refetch: refetchIPAccessList,
    error: ipAccessListError
  } = useUserServiceGetAPITokenIPAccessList({
    query: {
      retry: false
    }
  })

  const ipAccessList = ipAccessListResp?.data?.accessList
  const isIPAccessListNotConfigured =
    (ipAccessListError as any)?.response?.status === 404

  const getData = (params?: Partial<PageInfo>) =>
    userServiceListAPITokens({
      page: params?.page,
      perPage: params?.pageSize,
      nameLike: nameLike || undefined,
      statusIs: showInactiveTokens
        ? undefined
        : UserServiceListAPITokensStatusIs.API_TOKEN_STATUS_ACTIVE
    }).then((response) => toListDataResponse(response, (data) => data.tokens))

  const {
    dataSource,
    loading,
    reload,
    resetPageIndex,
    paginationProps,
    onTableChange
  } = useTable<ListData<V1APIToken>>(getData, [], {
    pagination: true,
    deps: [showInactiveTokens, nameLike]
  })

  const handleNameSearch = (value: string) => {
    setNameLike(value.trim())
    resetPageIndex()
  }

  const sortedDataSource = useMemo(() => {
    const statusOrder: Record<string, number> = {
      [V1APITokenStatus.API_TOKEN_STATUS_ACTIVE]: 0,
      [V1APITokenStatus.API_TOKEN_STATUS_INACTIVE]: 1
    }

    return [...(dataSource || [])].sort((a, b) => {
      const statusDiff =
        (statusOrder[a.status || ''] ?? 99) -
        (statusOrder[b.status || ''] ?? 99)
      if (statusDiff !== 0) {
        return statusDiff
      }

      return Number(b.createdAt || 0) - Number(a.createdAt || 0)
    })
  }, [dataSource])

  const handleRevokeToken = useCallback(
    (tokenName?: string) => {
      if (!tokenName) {
        return
      }

      Modal.confirm({
        title: 'Revoke API Token',
        content: `Are you sure to revoke token ${tokenName}?`,
        okButtonProps: {
          danger: true
        },
        onOk: async () => {
          try {
            await userServiceDeleteAPIToken(tokenName)
            message.success('API token revoked')
            reload()
          } catch (error) {
            Modal.error({
              title: error?.response?.data?.errcode || 'Request Failed',
              content:
                error?.response?.data?.errmsg ||
                error?.message ||
                'Failed to revoke API token'
            })
          }
        }
      })
    },
    [reload]
  )

  const columns: ColumnsType<V1APIToken> = useMemo(
    () => [
      {
        title: 'Name',
        dataIndex: 'name',
        render: (value) => value || '-',
        width: 200
      },
      {
        title: 'Comment',
        dataIndex: 'comment',
        render: (value) => value || '-',
        width: 300
      },
      {
        title: 'Privilege',
        dataIndex: 'privilege',
        render: (value) => {
          if (value === V1APITokenPrivilege.API_TOKEN_PRIVILEGE_READWRITE) {
            return 'Read Write'
          }

          if (value === V1APITokenPrivilege.API_TOKEN_PRIVILEGE_READONLY) {
            return 'Read Only'
          }

          return '-'
        },
        width: 150
      },
      {
        title: 'Created At',
        dataIndex: 'createdAt',
        render: (value) => toLocal(value) || '-',
        width: 200
      },
      {
        title: 'Expire At',
        dataIndex: 'expireAt',
        render: (value) => toLocal(value) || '-',
        width: 200
      },
      {
        title: 'Status',
        dataIndex: 'status',
        render: (value) => {
          if (value === V1APITokenStatus.API_TOKEN_STATUS_ACTIVE) {
            return <Tag color="success">Active</Tag>
          }

          if (value === V1APITokenStatus.API_TOKEN_STATUS_INACTIVE) {
            return <Tag>Inactive</Tag>
          }

          return '-'
        },
        width: 150
      },
      {
        title: 'Actions',
        render: (_: any, record) => (
          <Button
            type="ghost"
            danger
            onClick={() => handleRevokeToken(record.name)}
            disabled={
              !record.name ||
              record.status === V1APITokenStatus.API_TOKEN_STATUS_INACTIVE
            }
          >
            Revoke
          </Button>
        )
      }
    ],
    [handleRevokeToken]
  )

  const ipRuleColumns: ColumnsType<V1APITokenIPRule> = useMemo(
    () => [
      {
        title: 'IP Address',
        dataIndex: 'cidr',
        render: (value) => value || '-'
      },
      {
        title: 'Description',
        dataIndex: 'description',
        render: (value) => value || '-'
      }
    ],
    []
  )

  const handleCreateToken = async (payload: CreateAPITokenFormType) => {
    try {
      const resp = (
        await userServiceGenerateAPIToken({
          name: payload.name,
          comment: payload.comment,
          expireAt: String(payload.expire_at.unix()),
          privilege: payload.privilege
        })
      ).data
      setCreatedToken(resp.token || '')
      setCreatedTokenVisible(true)

      setCreateTokenVisible(false)
      await reload()
    } catch (error) {
      Modal.error({
        title: error?.response?.data?.errcode || 'Request Failed',
        content:
          error?.response?.data?.errmsg ||
          error?.message ||
          'Failed to create API token'
      })
    }
  }

  const openEditIPAccessListModal = () => {
    const allowAll = !!ipAccessList?.allowAll
    const normalizedRules = (ipAccessList?.rules || []).map((rule) => ({
      cidr: rule.cidr || '',
      description: rule.description || ''
    }))

    const initialValues: EditIPAccessListFormType = {
      allow_all: allowAll,
      rules:
        !allowAll && normalizedRules.length === 0
          ? [{ cidr: '', description: '' }]
          : normalizedRules
    }

    setIPAccessListFormInitialValues(initialValues)
    setEditIPAccessListVisible(true)
  }

  const handleUpdateIPAccessList = async (
    payload: EditIPAccessListFormType
  ) => {
    try {
      const allowAll = !!payload.allow_all
      const sourceRules =
        payload.rules !== undefined
          ? payload.rules
          : allowAll
          ? ipAccessList?.rules || []
          : []

      const normalizedRules = sourceRules
        .map((rule) => ({
          cidr: rule.cidr?.trim(),
          description: rule.description?.trim()
        }))
        .filter((rule) => !!rule.cidr)

      await userServiceUpsertAPITokenIPAccessList({
        allowAll,
        rules: normalizedRules
      })

      message.success('IP access list updated')
      setEditIPAccessListVisible(false)
      await refetchIPAccessList()
    } catch (error) {
      Modal.error({
        title: error?.response?.data?.errcode || 'Request Failed',
        content:
          error?.response?.data?.errmsg ||
          error?.message ||
          'Failed to update IP access list'
      })
    }
  }

  return (
    <Space direction="vertical" size={16} style={{ width: '100%' }}>
      <Card title="User Info">
        <Descriptions column={1} size="small">
          <Descriptions.Item label="Name">
            {operatorName || '-'}
          </Descriptions.Item>
          <Descriptions.Item label="Email">
            {userEmail || '-'}
          </Descriptions.Item>
          <Descriptions.Item label="Roles">
            {roleNames.length > 0 ? roleNames.join(', ') : '-'}
          </Descriptions.Item>
        </Descriptions>
      </Card>

      <Card
        title={
          <span>
            API Tokens{' '}
            <Typography.Link
              href="https://pingcap.feishu.cn/wiki/SEVIwkQXuic6Q0kUtg2cm5Gonsd"
              target="_blank"
              rel="noopener noreferrer"
              style={{ fontSize: 12 }}
            >
              Info
            </Typography.Link>
          </span>
        }
      >
        <ListToolBar
          title={
            <Space size={12}>
              <Input.Search
                allowClear
                placeholder="Search by token name"
                style={{ width: 280 }}
                onSearch={handleNameSearch}
                onChange={(event) => {
                  if (!event.target.value) {
                    handleNameSearch('')
                  }
                }}
              />
              <Checkbox
                checked={showInactiveTokens}
                onChange={(event) => {
                  setShowInactiveTokens(event.target.checked)
                  resetPageIndex()
                }}
              >
                show inactive tokens
              </Checkbox>
            </Space>
          }
          actions={[
            <Button type="primary" onClick={() => setCreateTokenVisible(true)}>
              Generate API Token
            </Button>,
            <Button onClick={() => reload()}>Reload</Button>
          ]}
        />

        <Table<V1APIToken>
          columns={columns}
          rowKey={(record) => record.id || record.name || ''}
          dataSource={sortedDataSource}
          loading={loading}
          pagination={paginationProps}
          onChange={onTableChange}
          size="small"
        />

        <div style={{ marginTop: 24 }}>
          <div
            style={{
              display: 'flex',
              justifyContent: 'space-between',
              alignItems: 'center',
              marginBottom: 12
            }}
          >
            <Typography.Text strong style={{ fontSize: 14 }}>
              IP Access List
            </Typography.Text>
            <Button onClick={openEditIPAccessListModal}>Edit IP Address</Button>
          </div>

          {isIPAccessListNotConfigured ? (
            <Alert
              type="warning"
              showIcon
              message="No IP Access List configured. Access from anywhere is allowed by default. It's not recommended to allow any IP address to use your api token."
            />
          ) : ipAccessList?.allowAll ? (
            <Alert
              type="warning"
              showIcon
              message="Allow access from anywhere. It's not recommended to allow any IP address to use your api token."
            />
          ) : (
            <Table<V1APITokenIPRule>
              columns={ipRuleColumns}
              rowKey={(record, index) =>
                `${record.cidr || 'ip-rule'}-${index || 0}`
              }
              dataSource={ipAccessList?.rules || []}
              loading={ipAccessListLoading}
              pagination={false}
              locale={{
                emptyText: (
                  <Empty
                    description="No IP rules"
                    image={Empty.PRESENTED_IMAGE_SIMPLE}
                  />
                )
              }}
              size="small"
            />
          )}
        </div>

        <CreateAPITokenForm
          visible={createTokenVisible}
          onSubmit={handleCreateToken}
          onCancel={() => setCreateTokenVisible(false)}
        />

        <Modal
          visible={createdTokenVisible}
          title="API Token Created"
          width={560}
          footer={[
            <Button
              key="ok"
              type="primary"
              onClick={() => setCreatedTokenVisible(false)}
            >
              OK
            </Button>
          ]}
          onCancel={() => setCreatedTokenVisible(false)}
        >
          <div>
            <p>
              API token has been created. Please save it now, it will not appear
              again.
            </p>
            <CodeBlock
              copyContent={createdToken}
              withCopyButton
              onCopyClick={() => message.info('Copied')}
            >
              {createdToken || '-'}
            </CodeBlock>
          </div>
        </Modal>

        <EditIPAccessListForm
          visible={editIPAccessListVisible}
          initValues={ipAccessListFormInitialValues}
          onSubmit={handleUpdateIPAccessList}
          onCancel={() => setEditIPAccessListVisible(false)}
        />
      </Card>
    </Space>
  )
}
