import { ReloadOutlined, DownOutlined } from '@ant-design/icons'
import { json as jsonLang } from '@codemirror/lang-json'
import CodeMirror from '@uiw/react-codemirror'
import {
  Alert,
  Button,
  Card,
  Descriptions,
  Divider,
  Dropdown,
  Empty,
  Form,
  Modal,
  message,
  Space,
  Spin,
  Typography
} from 'antd'
import type { MenuProps } from 'antd'
import { detailedDiff } from 'deep-object-diff'
import type { CSSProperties } from 'react'
import { useEffect, useMemo, useCallback, useState } from 'react'
import { useParams } from 'react-router-dom'

import {
  clusterServiceGetTrafficReplay,
  clusterServiceDeleteTrafficReplay,
  clusterServiceStartTrafficReplay,
  clusterServiceStopTrafficReplay,
  clusterServiceUpdateTrafficReplay
} from 'apiClient/services/devops'
import type { ClusterTrafficReplay } from 'apiClient/services/devops/interface'
import { ClusterDetailLinkPopover } from 'components/DetailLinkPopover/ClusterDetailLinkPopover'
import { TenantDetailLinkPopover } from 'components/DetailLinkPopover/TenantDetailLinkPopover'
import { toLocal } from 'utils/time'

import ReplayRequestForm, {
  ReplayRequestFormValues,
  buildUpdateReplayRequest,
  buildReplaySpecFromForm
} from './Forms/ReplayRequestForm'
import { RenderStateTag, RenderPhaseTag } from './helper'

const { Text } = Typography
const halfWidthDividerStyle: CSSProperties = { margin: '8px 0' }
type ReplayAction = 'start' | 'stop' | 'delete' | 'update'
type MenuClickHandler = NonNullable<MenuProps['onClick']>

export default function ReplayDetail() {
  const { org_id, cluster_id, replay_id } = useParams<{
    org_id: string
    cluster_id: string
    replay_id: string
  }>()
  const [replay, setReplay] = useState<ClusterTrafficReplay>()
  const [loading, setLoading] = useState(false)
  const [actionLoading, setActionLoading] = useState<ReplayAction | null>(null)
  const [isUpdateModalVisible, setIsUpdateModalVisible] = useState(false)
  const [updateSubmitting, setUpdateSubmitting] = useState(false)
  const [updateForm] = Form.useForm<ReplayRequestFormValues>()
  const updateFormInitialValues = useMemo(
    () => (replay ? buildReplayFormInitialValues(replay) : undefined),
    [replay]
  )

  const fetchReplay = useCallback(async () => {
    if (!replay_id || !cluster_id || !org_id) {
      return
    }

    try {
      setLoading(true)
      const response = await clusterServiceGetTrafficReplay(replay_id, {
        cluster_id,
        tenant_id: org_id
      })
      const detail = response.data.replay
      setReplay(detail)
    } catch (error) {
      const err = error as any
      const errMsg =
        err?.response?.data?.errmsg ??
        err?.message ??
        'Failed to load replay detail'
      message.error(errMsg)
    } finally {
      setLoading(false)
    }
  }, [replay_id, cluster_id, org_id])

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

  const actionDisabledMap = useMemo<Record<ReplayAction, boolean>>(() => {
    const defaultDisabled: Record<ReplayAction, boolean> = {
      update: true,
      start: true,
      stop: true,
      delete: true
    }

    if (actionLoading) {
      return { ...defaultDisabled }
    }

    if (!replay) {
      return { ...defaultDisabled }
    }

    const state = replay.current_state ?? 'REPLAY_CURRENT_STATE_UNSPECIFIED'
    const isDeletingOrDeleted =
      state === 'REPLAY_CURRENT_STATE_DELETING' ||
      state === 'REPLAY_CURRENT_STATE_DELETED'

    if (isDeletingOrDeleted) {
      return { ...defaultDisabled }
    }

    const startBlockedStates = new Set([
      'REPLAY_CURRENT_STATE_RUNNING',
      'REPLAY_CURRENT_STATE_STARTING',
      'REPLAY_CURRENT_STATE_DEPLOYING'
    ])
    const stopAllowedStates = new Set([
      'REPLAY_CURRENT_STATE_RUNNING',
      'REPLAY_CURRENT_STATE_STARTING'
    ])

    return {
      update: false,
      start: startBlockedStates.has(state),
      stop: !stopAllowedStates.has(state),
      delete: false
    }
  }, [actionLoading, replay])

  const handleAction = async (action: ReplayAction) => {
    if (!replay_id || !cluster_id || !org_id) {
      return
    }

    const payload = { cluster_id, tenant_id: org_id }
    try {
      if (action === 'update') {
        setIsUpdateModalVisible(true)
        return
      }

      setActionLoading(action)

      var resp: number | undefined = 0
      if (action === 'start') {
        resp = (await clusterServiceStartTrafficReplay(replay_id, payload)).data
          .instance_id
      } else if (action === 'stop') {
        resp = (await clusterServiceStopTrafficReplay(replay_id, payload)).data
          .instance_id
      } else if (action === 'delete') {
        resp = (await clusterServiceDeleteTrafficReplay(replay_id, payload))
          .data.instance_id
      } else {
        throw new Error(`Unknown action: ${action}`)
      }
      Modal.success({
        title: `Traffic Replay ${action.toUpperCase()} Operation Created`,
        content: (
          <div>
            <p>
              The operation has been created.
              <br></br>
              However, you should go to to the <b>Detail</b> Page to check the
              Approval information. Click <b>OK</b> will redirect you to that
              page.
            </p>
          </div>
        ),
        onOk() {
          window.open(`/operations/${resp}`, '_blank')
        }
      })

      fetchReplay()
    } catch (error) {
      const err = error as any
      const errMsg =
        err?.response?.data?.errmsg ??
        err?.message ??
        `Failed to ${action} replay`
      message.error(errMsg)
    } finally {
      setActionLoading(null)
    }
  }

  const actionMenuItems = useMemo<MenuProps['items']>(
    () => [
      { key: 'update', label: 'Update', disabled: actionDisabledMap.update },
      { key: 'start', label: 'Start', disabled: actionDisabledMap.start },
      { key: 'stop', label: 'Stop', disabled: actionDisabledMap.stop },
      {
        key: 'delete',
        label: 'Delete',
        danger: true,
        disabled: actionDisabledMap.delete
      }
    ],
    [actionDisabledMap]
  )

  const handleUpdateSubmit = async () => {
    if (!replay_id || !cluster_id || !org_id) {
      return
    }

    try {
      const values = await updateForm.validateFields()
      setUpdateSubmitting(true)
      const payload = buildUpdateReplayRequest(values)

      if (replay) {
        const initialPayload = buildUpdateReplayRequest(
          buildReplayFormInitialValues(replay)
        )
        const changedPayload = detailedDiff(initialPayload, payload)
        payload.changed_replay_spec = JSON.stringify(
          changedPayload,
          (key, value) => (value === undefined ? '__DELETED__' : value)
        )
      }

      var resp = (await clusterServiceUpdateTrafficReplay(replay_id, payload))
        .data.instance_id

      Modal.success({
        title: 'Traffic Replay Update Operation Created',
        content: (
          <div>
            <p>
              The operation has been created.
              <br></br>
              However, you should go to to the <b>Detail</b> Page to check the
              Approval information. Click <b>OK</b> will redirect you to that
              page.
            </p>
          </div>
        ),
        onOk() {
          window.open(`/operations/${resp}`, '_blank')
        }
      })

      setIsUpdateModalVisible(false)
      fetchReplay()
    } catch (error) {
      if ((error as any)?.errorFields) {
        return
      }
      const err = error as any
      const errMsg =
        err?.response?.data?.errmsg ?? err?.message ?? 'Failed to update replay'
      message.error(errMsg)
    } finally {
      setUpdateSubmitting(false)
    }
  }

  const handleMenuClick: MenuClickHandler = ({ key }) => {
    const action = key as ReplayAction
    const confirmConfigs: Partial<
      Record<
        ReplayAction,
        { title: string; content: string; okText: string; danger?: boolean }
      >
    > = {
      start: {
        title: 'Start replay?',
        content: 'Replay will begin executing traffic. Continue?',
        okText: 'Start'
      },
      stop: {
        title: 'Stop replay?',
        content: 'Replay traffic will be halted. Continue?',
        okText: 'Stop'
      },
      delete: {
        title: 'Delete replay?',
        content: 'This action cannot be undone. Proceed with deletion?',
        okText: 'Delete',
        danger: true
      },
      update: undefined
    }

    const confirmConfig = confirmConfigs[action]
    if (confirmConfig) {
      Modal.confirm({
        title: confirmConfig.title,
        content: confirmConfig.content,
        okText: confirmConfig.okText,
        okButtonProps: confirmConfig.danger ? { danger: true } : undefined,
        cancelText: 'Cancel',
        onOk: () => handleAction(action)
      })
      return
    }

    handleAction(action)
  }

  useEffect(() => {
    if (isUpdateModalVisible && updateFormInitialValues) {
      updateForm.setFieldsValue(updateFormInitialValues)
    }
  }, [isUpdateModalVisible, updateFormInitialValues, updateForm])

  if (loading || !replay) {
    return (
      <Spin size="large" spinning={loading} tip="Loading replay detail..." />
    )
  }

  return (
    <>
      <Space direction="vertical" size="large" style={{ width: '100%' }}>
        <Card
          bodyStyle={{ padding: '10px 8px' }}
          title={
            <span style={{ fontSize: 20, fontWeight: 600 }}>Replay Detail</span>
          }
          extra={
            <Space>
              <Dropdown
                menu={{ items: actionMenuItems, onClick: handleMenuClick }}
                placement="bottomRight"
              >
                <Button type="primary" loading={Boolean(actionLoading)}>
                  Actions
                  <DownOutlined />
                </Button>
              </Dropdown>
              <Button
                icon={<ReloadOutlined />}
                onClick={fetchReplay}
                loading={loading}
              ></Button>
            </Space>
          }
        >
          <Alert
            message="More Information"
            description={
              <span>
                More information can be found in the document:{' '}
                <a
                  href="https://pingcap.feishu.cn/wiki/A0LVwIJeuiQJ7wk8bh7cPZqrnh0"
                  target="_blank"
                  rel="noreferrer"
                >
                  Traffic Mirroring Operation Guide on OPS
                </a>
                .
              </span>
            }
            type="info"
            showIcon
          />
          <Space direction="vertical" size={24} style={{ width: '100%' }}>
            <Card
              type="inner"
              title={
                <span style={{ fontSize: 18, fontWeight: 600 }}>Overview</span>
              }
            >
              <Descriptions column={2} size="small">
                <Descriptions.Item span={2} label="Replay ID">
                  {replay.replay_id}
                </Descriptions.Item>
                <Descriptions.Item label="Tenant ID">
                  <TenantDetailLinkPopover
                    tenantId={replay.org_id!}
                    text={replay.org_id!}
                  />
                </Descriptions.Item>
                <Descriptions.Item label="Project ID">
                  {replay.project_id}
                </Descriptions.Item>
                <Descriptions.Item label="Target Cluster ID">
                  <ClusterDetailLinkPopover
                    clusterId={replay.cluster_id!}
                    text={replay.cluster_id!}
                  />
                </Descriptions.Item>
                <Descriptions.Item label="Source Cluster ID">
                  <ClusterDetailLinkPopover
                    clusterId={replay.source_cluster_id!}
                    text={replay.source_cluster_id!}
                  />
                </Descriptions.Item>
                <Descriptions.Item label="Current State">
                  {RenderStateTag(replay.current_state, 'current')}
                </Descriptions.Item>
                <Descriptions.Item label="Desired State">
                  {RenderStateTag(replay.desired_state, 'desired')}
                </Descriptions.Item>
                <Descriptions.Item label="Created At">
                  {toLocal(replay.created_at)}
                </Descriptions.Item>
                <Descriptions.Item label="Updated At">
                  {toLocal(replay.updated_at)}
                </Descriptions.Item>
              </Descriptions>
            </Card>

            <Card
              type="inner"
              title={
                <span style={{ fontSize: 18, fontWeight: 600 }}>Spec</span>
              }
            >
              <Descriptions column={2} size="small">
                <Descriptions.Item label="Region">
                  {replay.region}
                </Descriptions.Item>
                <Descriptions.Item label="Cloud Provider">
                  {replay.cloud_provider}
                </Descriptions.Item>
                <Descriptions.Item label="Replicas">
                  {replay.replicas}
                </Descriptions.Item>
                <Descriptions.Item label="Replay Image">
                  {replay.replay_image}
                </Descriptions.Item>
              </Descriptions>

              <Divider style={halfWidthDividerStyle} />
              <Text strong>Task Resource</Text>
              <Descriptions column={2} size="small">
                <Descriptions.Item label="Task Instance Type">
                  {replay.task_resources?.instance_type}
                </Descriptions.Item>
                <Descriptions.Item label="Task Storage Size">
                  {replay.task_resources?.storage_size}
                </Descriptions.Item>
              </Descriptions>

              <Divider style={halfWidthDividerStyle} />
              <div>
                <Text strong>Source Audit Credential</Text>
                {renderJSONBlock(
                  replay.source_audit_credential,
                  'Not configured'
                )}
              </div>

              {replay.replay_config && (
                <div>
                  <Divider style={halfWidthDividerStyle} />
                  <Text strong>Config</Text>
                  <Descriptions column={2} size="small">
                    <Descriptions.Item label="Username">
                      {replay.replay_config.username}
                    </Descriptions.Item>
                  </Descriptions>
                  {renderJSONBlock(
                    replay.replay_config.replay_config,
                    'Replay config payload is empty'
                  )}
                </div>
              )}

              <Divider style={halfWidthDividerStyle} />
              <Text strong>Tasks</Text>
              {renderJSONBlock(replay.replay_tasks, 'No replay tasks')}
            </Card>

            <Card
              type="inner"
              title={
                <span style={{ fontSize: 18, fontWeight: 600 }}>Status</span>
              }
            >
              {replay.replay_status && (
                <div>
                  <Descriptions column={2} size="small">
                    <Descriptions.Item label="Phase">
                      {RenderPhaseTag(replay.replay_status?.phase)}
                    </Descriptions.Item>
                    <Descriptions.Item label="Message">
                      {replay.replay_status?.message}
                    </Descriptions.Item>
                    <Descriptions.Item label="AWS Node Role ARN">
                      {replay.replay_status?.aws_node_role_arn}
                    </Descriptions.Item>
                    <Descriptions.Item label="Last Update Time">
                      {toLocal(replay.replay_status.last_update_time)}
                    </Descriptions.Item>
                  </Descriptions>

                  <Divider style={halfWidthDividerStyle} />
                  <Text strong>Tasks Statuses</Text>
                  {renderJSONBlock(
                    replay.replay_status.tasks,
                    'No replay task info available'
                  )}
                </div>
              )}
            </Card>
          </Space>
        </Card>
      </Space>

      <Modal
        destroyOnClose
        title="Update Replay"
        open={isUpdateModalVisible}
        onOk={handleUpdateSubmit}
        onCancel={() => {
          setIsUpdateModalVisible(false)
        }}
        okText="Save"
        cancelText="Cancel"
        confirmLoading={updateSubmitting}
        width={960}
      >
        {updateFormInitialValues ? (
          <ReplayRequestForm
            tenant_id={updateFormInitialValues.tenant_id}
            project_id={updateFormInitialValues.project_id}
            cluster_id={updateFormInitialValues.cluster_id}
            isUpdate={true}
            form={updateForm}
            initialValues={updateFormInitialValues}
          />
        ) : (
          <Spin />
        )}
      </Modal>
    </>
  )
}

function buildReplayFormInitialValues(
  replay: ClusterTrafficReplay
): ReplayRequestFormValues {
  const replayConfig = replay.replay_config?.replay_config as
    | (Record<string, unknown> & {
        replay_start_time?: string
        run_start_time?: string
        custom_arguments?: Record<string, string>
      })
    | undefined

  const configArgumentsEntries = replayConfig?.custom_arguments
    ? Object.entries(replayConfig.custom_arguments)
    : []
  const configCustomArguments = configArgumentsEntries.map(([key, value]) => ({
    key,
    value
  }))

  const replayTasksJson = replay.replay_tasks?.length
    ? JSON.stringify(replay.replay_tasks, null, 2)
    : undefined

  const sourceAudit = replay.source_audit_credential
  let auditProvider: ReplayRequestFormValues['auditProvider']
  if (sourceAudit?.aws) {
    auditProvider = 'aws'
  } else if (sourceAudit?.aliyun) {
    auditProvider = 'aliyun'
  }

  const replayWithSpec = replay as ClusterTrafficReplay & {
    config_replay_start_time?: string
    config_run_start_time?: string
  }

  return {
    tenant_id: replay.org_id ?? '',
    project_id: replay.project_id ?? '',
    cluster_id: replay.cluster_id ?? '',
    source_cluster_id: replay.source_cluster_id ?? '',
    database_username: replay.replay_config?.username,
    database_password: '', // Do not fill in password, only allow user to update it if needed
    config_replay_start_time:
      replayWithSpec.config_replay_start_time ??
      replayConfig?.replay_start_time,
    config_run_start_time:
      replayWithSpec.config_run_start_time ?? replayConfig?.run_start_time,
    replay_image: replay.replay_image,
    replicas: replay.replicas,
    cloud_provider: replay.cloud_provider,
    region: replay.region,
    config_custom_arguments: configCustomArguments,
    replayTasksJson,
    enableAuditLog: Boolean(sourceAudit?.aws || sourceAudit?.aliyun),
    enableReplayConfigCustomParameters: configCustomArguments.length > 0,
    enableReplayTasks: Boolean(replayTasksJson),
    enableTaskResources: Boolean(replay.task_resources),
    auditProvider,
    awsAudit: sourceAudit?.aws,
    aliyunAudit: sourceAudit?.aliyun,
    task_resources: replay.task_resources
  }
}

function renderJSONBlock(value: unknown | undefined, emptyText: string) {
  if (value == undefined) {
    return (
      <Empty description={emptyText} image={Empty.PRESENTED_IMAGE_SIMPLE} />
    )
  }

  let content = ''
  try {
    content = JSON.stringify(value, null, 2) ?? ''
  } catch (error) {
    content = String(value)
  }

  return (
    <CodeMirror
      value={content}
      editable={false}
      extensions={[jsonLang()]}
      basicSetup={{
        lineNumbers: true,
        foldGutter: true,
        highlightActiveLine: false
      }}
      style={{
        border: '1px solid #d9d9d9',
        borderRadius: 4,
        fontSize: 12,
        overflow: 'hidden'
      }}
    />
  )
}
