import { CodeBlock } from '@tidbcloud/uikit/biz'
import { Spin, Space, Tabs, Alert, message, Select, Button } from 'antd'
import { useEffect, useState } from 'react'
import useProfileContext from 'useProfileContext'

import { jumpControllerGetConnection } from 'apiClient/services/devops'
import {
  JumpConnection,
  JumpAuthorization,
  JumpControllerGetConnectionMethod
} from 'apiClient/services/devops/interface'
import jpegSSHUsage from 'images/jumpserver_ssh.jpeg'

import { GetDestinationsFromUnion, GetJumpCommand } from './util'

type ConnectionTab =
  | typeof JumpControllerGetConnectionMethod.web_terminal
  | typeof JumpControllerGetConnectionMethod.ssh
  | typeof JumpControllerGetConnectionMethod.gateway

const DEFAULT_TAB = JumpControllerGetConnectionMethod.web_terminal

export default function JumpServerConnect({
  auth,
  open
}: {
  auth: JumpAuthorization
  open: boolean
}) {
  const {
    profile: { userEmail }
  } = useProfileContext()

  const [curJumpID, setCurJumpID] = useState<number>(auth.jumps![0].id!)
  const [activeTabKey, setActiveTabKey] = useState<ConnectionTab>(DEFAULT_TAB)
  const [connectionCache, setConnectionCache] = useState<JumpConnection>({})
  const [loadingByMethod, setLoadingByMethod] = useState<
    Record<ConnectionTab, boolean>
  >({
    web_terminal: false,
    ssh: false,
    gateway: false
  })

  async function fetchConnection(method: ConnectionTab, force = false) {
    if (!open || !auth.id) return
    if (!force && connectionCache[method]) return

    setLoadingByMethod((prev) => ({
      ...prev,
      [method]: true
    }))

    try {
      const resp = await jumpControllerGetConnection(auth.id, {
        method
      })

      setConnectionCache((prev) => ({
        ...prev,
        ...(resp.data.connection || {})
      }))
    } finally {
      setLoadingByMethod((prev) => ({
        ...prev,
        [method]: false
      }))
    }
  }

  useEffect(() => {
    if (!open) return

    setCurJumpID(auth.jumps![0].id!)
    setActiveTabKey(DEFAULT_TAB)
    setConnectionCache({})
    setLoadingByMethod({
      web_terminal: false,
      ssh: false,
      gateway: false
    })
    fetchConnection(DEFAULT_TAB, true)
  }, [open, auth.id])

  const handleTabChange = (key: string) => {
    const method = key as ConnectionTab
    setActiveTabKey(method)
    fetchConnection(method)
  }

  const isWebTabReady = !!connectionCache.web_terminal
  const isSshTabReady = !!connectionCache.ssh
  const isGatewayEnabled = !!auth.enable_gateway_access

  return (
    <>
      <Space direction="vertical" style={{ width: '100%' }}>
        <div>
          <div style={{ marginBottom: 8 }}>Choose Destination:</div>
          <Select
            value={curJumpID}
            style={{ width: 300, marginBottom: '10px' }}
            options={auth.jumps!.map((jump) => ({
              label: GetDestinationsFromUnion(jump.destination),
              value: jump.id
            }))}
            onChange={(value) => {
              setCurJumpID(value)
            }}
          />
        </div>

        <Tabs activeKey={activeTabKey} onChange={handleTabChange} size="small">
          <Tabs.TabPane
            tab="Web Terminal"
            key={JumpControllerGetConnectionMethod.web_terminal}
          >
            {loadingByMethod.web_terminal || !isWebTabReady || !curJumpID ? (
              <Spin />
            ) : (
              <WebTerminal
                connection={connectionCache}
                command={GetJumpCommand(
                  auth.jumps!.find((j) => j.id === curJumpID)
                )}
              />
            )}
          </Tabs.TabPane>
          <Tabs.TabPane tab="SSH" key={JumpControllerGetConnectionMethod.ssh}>
            {loadingByMethod.ssh || !isSshTabReady || !curJumpID ? (
              <Spin />
            ) : (
              <SSH
                username={userEmail!}
                connection={connectionCache}
                command={GetJumpCommand(
                  auth.jumps!.find((j) => j.id === curJumpID)
                )}
              />
            )}
          </Tabs.TabPane>
          <Tabs.TabPane
            tab="Gateway"
            key={JumpControllerGetConnectionMethod.gateway}
            disabled={!isGatewayEnabled}
          >
            {loadingByMethod.gateway ? (
              <Spin />
            ) : (
              <Gateway connection={connectionCache} />
            )}
          </Tabs.TabPane>
        </Tabs>
      </Space>
    </>
  )
}

function WebTerminal({
  connection,
  command
}: {
  connection: JumpConnection
  command: string
}) {
  return (
    <Space direction="vertical" style={{ lineHeight: '1.6' }}>
      <div>
        1. Visit{' '}
        <Button
          type="primary"
          size="small"
          href={connection.web_terminal?.url}
          target="_blank"
        >
          Connection Link
        </Button>{' '}
        to connect to jumpserver web terminal.
      </div>
      <div style={{ paddingLeft: '15px' }}>
        <Alert
          message="Note"
          description={
            'If jumpserver asks you to login, please login and finish the MFA, then come back and click the above link again.'
          }
          type="info"
          showIcon
        />
      </div>

      <div> 2. Enter the following command. </div>
      <div style={{ paddingLeft: '15px' }}>
        <CodeBlock
          language="bash"
          copyContent={command}
          withCopyButton
          onCopyClick={() => message.info('Copied')}
        >
          {command}
        </CodeBlock>
      </div>
    </Space>
  )
}

function SSH({
  username,
  connection,
  command
}: {
  username: string
  connection: JumpConnection
  command: string
}) {
  return (
    <Space direction="vertical" style={{ lineHeight: '1.6' }}>
      <div>
        {' '}
        1. Connect to the jumpserver bastion with your local ssh client.{' '}
      </div>
      <div style={{ paddingLeft: '15px' }}>
        <CodeBlock
          language="bash"
          copyContent={`ssh -p 2222 ${username}@${
            connection.ssh?.address || ''
          }`}
          withCopyButton
          onCopyClick={() => message.info('Copied')}
        >
          {`ssh -p 2222 ${username}@${connection.ssh?.address || ''}`}
        </CodeBlock>
      </div>

      <div> 2. Use your jumpserver password and MFA code to login.</div>

      <div>
        {' '}
        3. Enter <b>'{connection.ssh?.base_asset_name || ''}'</b> to access the
        cluster.{' '}
      </div>
      <div style={{ paddingLeft: '15px' }}>
        <img src={jpegSSHUsage} alt="loading..." width={500} />
      </div>

      <div> 4. Enter the following command to connect to your jumppod. </div>
      <div style={{ paddingLeft: '15px' }}>
        <CodeBlock
          language="bash"
          copyContent={`kubectl exec -n ${
            connection.ssh?.jumppod_namespace || ''
          } ${connection.ssh?.jumppod_name || ''} -it -- bash`}
          withCopyButton
          onCopyClick={() => message.info('Copied')}
        >
          {`kubectl exec -n ${connection.ssh?.jumppod_namespace || ''} ${
            connection.ssh?.jumppod_name || ''
          } -it -- bash`}
        </CodeBlock>
      </div>

      <div> 5. Enter the following command. </div>
      <div style={{ paddingLeft: '15px' }}>
        <CodeBlock
          language="bash"
          copyContent={command}
          withCopyButton
          onCopyClick={() => message.info('Copied')}
        >
          {command}
        </CodeBlock>
      </div>
    </Space>
  )
}

function Gateway({ connection }: { connection: JumpConnection }) {
  const kubeconfig = connection.gateway?.kubeconfig
  const gatewayExampleCommand = `export KUBECONFIG=./kubeconfig.yaml

kubectl get ns`

  return (
    <Space direction="vertical" style={{ lineHeight: '1.6', width: '100%' }}>
      {!kubeconfig ? (
        <Alert
          showIcon
          type="warning"
          message="Gateway kubeconfig is unavailable."
          description="Gateway access may not be enabled for this authorization, or kubeconfig is not ready yet."
        />
      ) : (
        <>
          <div>1. Save the following kubeconfig content to a local file.</div>
          <div style={{ paddingLeft: '15px' }}>
            <CodeBlock
              language="yaml"
              copyContent={kubeconfig}
              withCopyButton
              onCopyClick={() => message.info('Copied')}
            >
              {kubeconfig}
            </CodeBlock>
          </div>
          <div>2. Use kubectl with that file, for example:</div>
          <div style={{ paddingLeft: '15px' }}>
            <CodeBlock
              language="bash"
              copyContent={gatewayExampleCommand}
              withCopyButton
              onCopyClick={() => message.info('Copied')}
            >
              {gatewayExampleCommand}
            </CodeBlock>
          </div>
        </>
      )}
    </Space>
  )
}
