import { PlusOutlined } from '@ant-design/icons'
import {
  Alert,
  Badge,
  Button,
  Checkbox,
  Divider,
  Form,
  Modal,
  Radio,
  Select,
  Table,
  Typography
} from 'antd'
import TextArea from 'antd/lib/input/TextArea'
import { ColumnsType } from 'antd/lib/table'
import { useCallback, useEffect, useMemo, useState } from 'react'
import { Link } from 'react-router-dom'
import { useLocation } from 'react-router-dom'
import useProfileContext from 'useProfileContext'

import {
  jumpControllerCreateInstance,
  jumpControllerGetUserOfApplicant,
  jumpControllerListAuthorizations,
  jumpControllerListAvailableDestinations
} from 'apiClient/services/devops'
import {
  JumpDestinationType,
  JumpJumpPrivilege,
  JumpJumpExpiration,
  JumpAuthorization,
  JumpControllerListAuthorizationsParams,
  JumpControllerListAuthorizationsPhase,
  JumpDestinationUnion,
  JumpCreateAuthorizationReq,
  JumpAuthorizationPhase
} from 'apiClient/services/devops/interface'
import { ClusterDetailLinkPopover } from 'components/DetailLinkPopover/ClusterDetailLinkPopover'
import { ResourcePoolDetailLinkPopover } from 'components/DetailLinkPopover/ResourcePoolDetailLinkPopover'
import {
  FormOption,
  FormSection,
  FormSectionGroup
} from 'components/FormSection'
import ModalForm from 'components/ModalForm'
import SearchBar from 'components/SearchBar'
import {
  MultiConditionSearchInput,
  SearchFilter,
  SearchOption
} from 'components/SearchBar/MultiConditionSearchBar'
import { ListToolBar, useTable } from 'components/Table'
import { toLocal } from 'pages/Devops/Maintenance/Detail'

import Activate from './Activate/Activate'
import JumpServerConnect from './JumpServerConnect'
import { GetDestinationsFromUnion } from './util'

const statusActionText = {
  created: 'created',
  approving: 'approving',
  notapproved: 'notapproved',
  creating: 'creating',
  creationfailed: 'creationfailed',
  expired: 'expired',
  canceled: 'canceled',
  initialized: 'initialized'
}

const statusActionColor = {
  created: 'green',
  approving: 'orange',
  notapproved: 'red',
  creating: 'blue',
  creationfailed: 'red',
  expired: 'grey',
  canceled: 'black',
  initialized: 'lime'
}

const formOptionItemStyle = {
  marginBottom: 0
}

export interface CreateAuthorizationForm {
  plane?: JumpDestinationType
  clusters?: string[]
  privilege?: JumpJumpPrivilege
  expiration?: JumpJumpExpiration
  reason?: string
  enable_gateway_access?: boolean
  extra?: { [key: string]: string }
}

export default function Authorizations({}: {}) {
  const location = useLocation()
  const urlSearchParams = new URLSearchParams(location.search)

  const [searchParams, setSearchParams] =
    useState<JumpControllerListAuthorizationsParams>({})
  const reloadInit = () => {
    return reload()
  }

  const [modalOpen, setModalOpen] = useState<boolean>(
    urlSearchParams.get('create') === 'true'
  )
  const [existUser, setExistUser] = useState<boolean | undefined>(undefined)
  const [reloadUser, setReloadUser] = useState(false)
  const [availableControlplaneClusters, setAvailableControlplaneClusters] =
    useState<string[]>([])
  const [availableServerlessClusters, setAvailableServerlesseClusters] =
    useState<string[]>([])
  const [showUnaccessible, setShowUnaccessible] = useState<boolean>(false)
  const [connectAuth, setConnectAuth] = useState<JumpAuthorization>()

  const {
    profile: { userEmail }
  } = useProfileContext()

  useEffect(() => {
    async function queryAvailableDestinations() {
      try {
        const dataControlPlane = (
          await jumpControllerListAvailableDestinations(
            JumpDestinationType.controlplane
          )
        ).data
        if (dataControlPlane.destinations)
          setAvailableControlplaneClusters(dataControlPlane.destinations)

        const dataServerless = (
          await jumpControllerListAvailableDestinations(
            JumpDestinationType.serverless
          )
        ).data
        if (dataServerless.destinations)
          setAvailableServerlesseClusters(dataServerless.destinations)
      } catch (e) {
        console.error(e)
      }
    }

    queryAvailableDestinations()
  }, [modalOpen])

  useEffect(() => {
    async function getUserOfApplicant() {
      const data = (await jumpControllerGetUserOfApplicant()).data
      if (data.user_id) {
        setExistUser(true)
      } else {
        setExistUser(false)
      }
    }
    getUserOfApplicant()
  }, [reloadUser])

  const search_options: SearchOption[] = [
    {
      key: 'applicant',
      label: 'Applicant',
      inputType: 'text',
      inputDefaultValue: userEmail
    },
    {
      key: 'phase',
      label: 'Phase',
      inputType: 'enum',
      inputEnums: Object.values(JumpAuthorizationPhase || {}).map((v) => ({
        label: v as string,
        value: v as string
      }))
    },
    {
      key: 'destination_id_like',
      label: 'Destination ID',
      inputType: 'text'
    },
    {
      key: 'destination_type_is',
      label: 'Destination Type',
      inputType: 'enum',
      inputEnums: Object.values(JumpDestinationType || {})
        .filter((v) => {
          return v !== JumpDestinationType.unspecified
        })
        .map((v) => ({
          label: v as string,
          value: v as string
        }))
    }
  ]

  const handleSearchOptionsChange = (filters: SearchFilter[]) => {
    let param = { ...searchParams }
    filters.forEach((filter) => {
      if (filter.key === 'applicant') {
        param.applicant = filter.value
      }
      if (filter.key === 'phase') {
        param.phase = filter.value as JumpControllerListAuthorizationsPhase
      }
      if (filter.key === 'destination_id_like') {
        param.destination_id_like = filter.value
      }
      if (filter.key === 'destination_type_is') {
        param.destination_type_is = filter.value as JumpDestinationType
      }
    })
    setSearchParams({ ...param })
    reload()
  }

  const handleConnect = (auth: JumpAuthorization) => {
    setConnectAuth(auth)
  }

  const getData = (params?: Partial<PageInfo>) =>
    jumpControllerListAuthorizations({
      page: params?.page,
      per_page: params?.pageSize,
      show_unaccessible: showUnaccessible,
      ...searchParams
    })

  const renderStatusCell = useCallback((_: any, record: JumpAuthorization) => {
    const status = record.phase
    if (status) {
      return (
        <Badge
          color={statusActionColor[status] ? statusActionColor[status] : 'grey'}
          text={statusActionText[status] ? statusActionText[status] : 'Unknown'}
        />
      )
    } else {
      return <></>
    }
  }, [])

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

  const AuthorizationModalFormFields = () => {
    return (
      <FormSectionGroup show_outline={false}>
        <FormSection title="">
          <FormOption
            title="Plane"
            description="Choose the destination plane firstly."
            required
          >
            <Form.Item
              name="plane"
              rules={[
                {
                  required: true,
                  message: 'Please select the plane!'
                }
              ]}
              style={formOptionItemStyle}
            >
              <Select
                style={{ width: 400 }}
                showSearch={true}
                options={[
                  {
                    value: JumpDestinationType.controlplane,
                    label: 'Control Plane'
                  },
                  {
                    value: JumpDestinationType.dedicated,
                    label: 'Dedicated Cluster'
                  },
                  {
                    value: JumpDestinationType.serverless,
                    label: 'Serverless Cluster'
                  },
                  {
                    value: JumpDestinationType.byoc,
                    label: 'Byoc Cluster'
                  },
                  {
                    value: JumpDestinationType.premium,
                    label: 'Premium Cluster'
                  },
                  {
                    value: JumpDestinationType.premium_resource_pool,
                    label: 'Premium Resource Pool'
                  }
                ]}
              />
            </Form.Item>
          </FormOption>
          <Form.Item
            noStyle
            shouldUpdate={(prevValues, currentValues) =>
              prevValues.plane !== currentValues.plane
            }
          >
            {({ getFieldValue }) => {
              if (getFieldValue('plane') === JumpDestinationType.controlplane) {
                return (
                  <FormOption
                    title="Clusters"
                    description="Select registered control plane cluster."
                    required
                  >
                    <Form.Item
                      name="clusters"
                      rules={[
                        {
                          required: true,
                          message: 'Please select control plane clusters!'
                        }
                      ]}
                      style={formOptionItemStyle}
                    >
                      <Select
                        mode="multiple"
                        style={{ width: 400 }}
                        options={availableControlplaneClusters.map((i) => {
                          return { value: i, label: i }
                        })}
                      />
                    </Form.Item>
                  </FormOption>
                )
              } else if (
                getFieldValue('plane') === JumpDestinationType.dedicated
              ) {
                return (
                  <FormOption
                    title="Clusters"
                    description="Input dedicated cluster IDs."
                    required
                  >
                    <Form.Item
                      name="clusters"
                      rules={[
                        { required: true, message: 'Please input cluster ids!' }
                      ]}
                      style={formOptionItemStyle}
                    >
                      <Select mode="tags" style={{ width: 400 }} />
                    </Form.Item>
                  </FormOption>
                )
              } else if (getFieldValue('plane') === JumpDestinationType.byoc) {
                return (
                  <FormOption
                    title="Bastion Names"
                    description="Input BYOC bastion names, eg 'tidbbyoc-bastion-us-west-2-<tenant>-tidb'."
                    required
                  >
                    <Form.Item
                      name="clusters"
                      rules={[
                        {
                          required: true,
                          message: 'Please input bastion names!'
                        }
                      ]}
                      style={formOptionItemStyle}
                    >
                      <Select mode="tags" style={{ width: 400 }} />
                    </Form.Item>
                  </FormOption>
                )
              } else if (
                getFieldValue('plane') === JumpDestinationType.serverless
              ) {
                return (
                  <FormOption
                    title="Clusters"
                    description="Select registered serverless clusters."
                    required
                  >
                    <Form.Item
                      name="clusters"
                      rules={[
                        {
                          required: true,
                          message: 'Please select serverless cluster!'
                        }
                      ]}
                      style={formOptionItemStyle}
                    >
                      <Select
                        mode="multiple"
                        style={{ width: 400 }}
                        options={availableServerlessClusters.map((i) => {
                          return { value: i, label: i }
                        })}
                      />
                    </Form.Item>
                  </FormOption>
                )
              } else if (
                getFieldValue('plane') === JumpDestinationType.premium
              ) {
                return (
                  <FormOption
                    title="Clusters"
                    description="Input premium cluster IDs."
                    required
                  >
                    <Form.Item
                      name="clusters"
                      rules={[
                        { required: true, message: 'Please input cluster ids!' }
                      ]}
                      style={formOptionItemStyle}
                    >
                      <Select mode="tags" style={{ width: 400 }} />
                    </Form.Item>
                  </FormOption>
                )
              } else if (
                getFieldValue('plane') ===
                JumpDestinationType.premium_resource_pool
              ) {
                return (
                  <FormOption
                    title="Resource Pools"
                    description="Input premium resource pool IDs."
                    required
                  >
                    <Form.Item
                      name="clusters"
                      rules={[
                        {
                          required: true,
                          message: 'Please input resource pool ids!'
                        }
                      ]}
                      style={formOptionItemStyle}
                    >
                      <Select mode="tags" style={{ width: 400 }} />
                    </Form.Item>
                  </FormOption>
                )
              }
              return null
            }}
          </Form.Item>
          <FormOption
            title="Privileges"
            description="Choose the access privilege for destinations."
            info_link="https://pingcap.feishu.cn/wiki/HSXRwxkyxiP8I7kIiegcnspBnpc?larkTabName=space#share-Gez0dYNU2o8MYsxIZhGcJe8unrh"
            required
          >
            <Form.Item
              noStyle
              shouldUpdate={(prevValues, currentValues) =>
                prevValues.plane !== currentValues.plane
              }
            >
              {({ getFieldValue, setFieldsValue }) => {
                if (getFieldValue('plane') === JumpDestinationType.byoc) {
                  setTimeout(() => setFieldsValue({ privilege: 'admin' }), 0)
                }
                return (
                  <Form.Item
                    name="privilege"
                    rules={[
                      { required: true, message: 'Please select privilege!' }
                    ]}
                    style={formOptionItemStyle}
                  >
                    <Select
                      style={{ width: 400 }}
                      defaultValue={'read_write'}
                      disabled={
                        getFieldValue('plane') === JumpDestinationType.byoc
                      }
                      options={[
                        { value: 'read_only', label: 'Read Only' },
                        { value: 'read_write', label: 'Read Write' },
                        { value: 'admin', label: 'Admin' }
                      ]}
                    />
                  </Form.Item>
                )
              }}
            </Form.Item>
          </FormOption>

          <FormOption title="Expiration" required>
            <Form.Item
              noStyle
              shouldUpdate={(prevValues, currentValues) =>
                prevValues.plane !== currentValues.plane
              }
            >
              {({ getFieldValue }) => (
                <Form.Item
                  name="expiration"
                  rules={[
                    {
                      required: true,
                      message: 'Please select expiration time!'
                    }
                  ]}
                  style={formOptionItemStyle}
                >
                  <Select
                    style={{ width: 400 }}
                    options={[
                      { value: '1h', label: '1 hour' },
                      { value: '3h', label: '3 hours' },
                      { value: '6h', label: '6 hours' },
                      { value: '12h', label: '12 hours' },
                      { value: '24h', label: '24 hours' },
                      { value: '3d', label: '72 hours' },
                      {
                        value: '7d',
                        label: '7 Days',
                        disabled: ![
                          JumpDestinationType.serverless,
                          JumpDestinationType.controlplane
                        ].includes(getFieldValue('plane'))
                      }
                    ]}
                  />
                </Form.Item>
              )}
            </Form.Item>
          </FormOption>
          <FormOption title="Reason" required>
            <Form.Item
              name="reason"
              rules={[{ required: true, message: 'Please fill in reason!' }]}
              style={formOptionItemStyle}
            >
              <TextArea style={{ width: 400 }}></TextArea>
            </Form.Item>
          </FormOption>
          <Form.Item
            noStyle
            shouldUpdate={(prevValues, currentValues) =>
              prevValues.plane !== currentValues.plane
            }
          >
            {({ getFieldValue }) => (
              <FormOption
                title="Enable Gateway Access"
                description="Access the destinations using a temporary kubeconfig, without logging in to the jump server."
                info_link="https://pingcap.feishu.cn/wiki/HSXRwxkyxiP8I7kIiegcnspBnpc?larkTabName=space#share-Tpr4dalrdoksSgxktJecbs6pnVc"
              >
                <Form.Item
                  name="enable_gateway_access"
                  style={formOptionItemStyle}
                >
                  <Radio.Group
                    disabled={
                      getFieldValue('plane') === JumpDestinationType.byoc
                    }
                    options={[
                      { label: 'Yes', value: true },
                      { label: 'No', value: false }
                    ]}
                  />
                </Form.Item>
              </FormOption>
            )}
          </Form.Item>
        </FormSection>
      </FormSectionGroup>
    )
  }

  const columns: ColumnsType<JumpAuthorization> = [
    {
      title: 'ID',
      render: (_: any, record) => {
        return record.id
      }
    },
    {
      title: 'Destinations',
      render: (_: any, record) => (
        <ul>
          {record.jumps?.map((j, index) => (
            <li key={index}>
              {GetDisplayTextFromUnion(j.destination_type, j.destination)}
            </li>
          ))}
        </ul>
      )
    },
    {
      title: 'Applicant',
      render: (_: any, record) => {
        return record.applicant
      }
    },
    {
      title: 'Reason',
      render: (_: any, record) => {
        return record.reason
      }
    },
    {
      title: 'Created At',
      render: (_: any, record) => {
        return toLocal(record.created_at)
      }
    },
    {
      title: 'Expire At',
      render: (_: any, record) => {
        return toLocal(record.expire_at)
      }
    },
    {
      title: 'Phase',
      render: renderStatusCell
    },
    {
      title: 'Action',
      render: (_: any, record) => (
        <div>
          <Button
            type="link"
            onClick={() => record.id && handleConnect(record)}
            disabled={
              !(record?.phase === 'created' && record?.applicant === userEmail)
            }
          >
            Connect
          </Button>
          <Button type="link">
            <Link to={`/jumps/${record.id}`}>Detail</Link>
          </Button>
        </div>
      )
    }
  ]

  const actions = useMemo(
    () => [
      <div
        style={{
          height: '32px',
          display: 'flex',
          alignItems: 'flex-end'
        }}
      >
        <Checkbox
          name="showUnaccessible"
          checked={showUnaccessible}
          onClick={() => {
            setShowUnaccessible(!showUnaccessible)
            reload()
          }}
        >
          Show unaccessible jumps
        </Checkbox>
      </div>,
      <MultiConditionSearchInput
        options={search_options}
        onChange={handleSearchOptionsChange}
      />,
      <Button
        type="primary"
        name="create"
        icon={<PlusOutlined />}
        onClick={() => {
          setModalOpen(!modalOpen)
        }}
      >
        Create Jump
      </Button>
    ],
    [showUnaccessible, userEmail]
  )

  const handleCreate = useCallback(
    async (payload: CreateAuthorizationForm) => {
      const req: JumpCreateAuthorizationReq = {
        destination_type: payload.plane,
        destinations: payload.clusters,
        enable_gateway_access: payload.enable_gateway_access,
        expiration: payload.expiration,
        privilege: payload.privilege,
        reason: payload.reason,
        extra: payload.extra
      }
      return jumpControllerCreateInstance(req)
        .then(() => {
          setModalOpen(false)
          reload()
        })
        .catch((e) => {
          // HACK: overide the default error of axios to enable showing error message in ModalForm
          if (e.response.data.errmsg && e.response.status)
            throw {
              response: {
                data: {
                  message: e.response.status + ': ' + e.response.data.errmsg
                }
              }
            }
          else throw e
        })
    },
    [reload]
  )

  const params = new URLSearchParams(window.location.search)
  const create = params.get('create')

  useEffect(() => {
    setModalOpen(create === 'true')
  }, [create])

  return (
    <div>
      <ListToolBar
        title={
          <span>
            <span style={{ fontSize: 20, fontWeight: 600 }}>Jump</span>{' '}
            <Typography.Link
              href="https://pingcap.feishu.cn/wiki/HSXRwxkyxiP8I7kIiegcnspBnpc"
              target="_blank"
              rel="noopener noreferrer"
              style={{ fontSize: 12 }}
            >
              Info
            </Typography.Link>
          </span>
        }
        actions={actions}
        reload={reloadInit}
      />

      {existUser === undefined || existUser === true ? (
        <></>
      ) : (
        <div>
          <Alert
            showIcon
            type="warning"
            message={<Activate reload={setReloadUser}></Activate>}
          />
          <Divider></Divider>
        </div>
      )}

      <Table<JumpAuthorization>
        columns={columns}
        rowKey="id"
        dataSource={dataSource}
        loading={loading}
        pagination={paginationProps}
        size="small"
        onChange={onTableChange}
      ></Table>

      <ModalForm<CreateAuthorizationForm>
        initValues={{
          plane: urlSearchParams.get('cluster_deploy_type')
            ? (urlSearchParams.get(
                'cluster_deploy_type'
              ) as JumpDestinationType)
            : undefined,
          clusters: urlSearchParams.get('cluster_id')
            ? urlSearchParams.get('cluster_id')!.split(',')
            : undefined,
          expiration: '12h',
          privilege: 'read_write',
          enable_gateway_access: false
        }}
        visible={!!modalOpen}
        name="jump server authorization"
        title="Create Jump"
        getFields={() => {
          return <AuthorizationModalFormFields />
        }}
        width={650}
        onSubmit={handleCreate}
        onCancel={() => {
          setModalOpen(false)
        }}
      />

      <Modal
        title={'Connect to Jumpserver'}
        open={connectAuth !== undefined}
        onCancel={() => setConnectAuth(undefined)}
        footer={null}
        width={1000}
      >
        <JumpServerConnect
          auth={connectAuth!}
          open={connectAuth !== undefined}
        />
      </Modal>
    </div>
  )
}

export function GetDisplayTextFromUnion(
  typ: string | undefined,
  union: JumpDestinationUnion | undefined
): JSX.Element {
  const id = GetDestinationsFromUnion(union)
  const text = typ + '.' + GetDestinationsFromUnion(union)

  if (
    typ === JumpDestinationType.dedicated ||
    typ == JumpDestinationType.premium
  ) {
    return (
      <ClusterDetailLinkPopover
        clusterId={id}
        text={text}
      ></ClusterDetailLinkPopover>
    )
  }
  if (typ === JumpDestinationType.premium_resource_pool) {
    return (
      <ResourcePoolDetailLinkPopover
        resourcePoolId={id}
        text={text}
      ></ResourcePoolDetailLinkPopover>
    )
  }
  return <span>{text}</span>
}
