import { InfoCircleOutlined } from '@ant-design/icons'
import { Alert, Button, Descriptions, Input, Popover, Spin } from 'antd'
import React, { useEffect, useMemo, useRef, useState } from 'react'

import { getTenant } from 'apiClient/services/devops'
import { TenantGetTenantResp } from 'apiClient/services/devops/interface'

export interface TenantSearchInputProps {
  value?: string
  onChange?: (value: string) => void
  disabled?: boolean
  placeholder?: string
  className?: string
  style?: React.CSSProperties
}

const DEFAULT_ERROR_MESSAGE = 'Failed to fetch tenant detail.'
const AUTO_OPEN_DELAY = 500

function getErrorMessage(error: unknown) {
  const axiosLikeError = error as {
    response?: { data?: { errmsg?: string } }
    message?: string
  }

  return (
    axiosLikeError?.response?.data?.errmsg ||
    axiosLikeError?.message ||
    DEFAULT_ERROR_MESSAGE
  )
}

const TenantSearchInput: React.FC<TenantSearchInputProps> = ({
  value,
  onChange,
  disabled,
  placeholder = 'Please input tenant id',
  className,
  style
}) => {
  const [innerValue, setInnerValue] = useState('')
  const [tenantInfo, setTenantInfo] = useState<TenantGetTenantResp>()
  const [curError, setCurError] = useState<string>()
  const [loading, setLoading] = useState(false)
  const [loadedTenantId, setLoadedTenantId] = useState<string>()
  const [isPopoverOpen, setIsPopoverOpen] = useState(false)
  const requestIdRef = useRef(0)

  const inputValue = value ?? innerValue
  const normalizedTenantId = useMemo(() => inputValue.trim(), [inputValue])

  useEffect(() => {
    requestIdRef.current += 1
    setTenantInfo(undefined)
    setCurError(undefined)
    setLoading(false)
    setLoadedTenantId(undefined)
    setIsPopoverOpen(false)
  }, [normalizedTenantId])

  useEffect(() => {
    if (disabled || !normalizedTenantId) {
      setIsPopoverOpen(false)
      return
    }

    const timer = window.setTimeout(() => {
      setIsPopoverOpen(true)
    }, AUTO_OPEN_DELAY)

    return () => {
      window.clearTimeout(timer)
    }
  }, [disabled, normalizedTenantId])

  const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>) => {
    const nextValue = event.target.value

    if (value === undefined) {
      setInnerValue(nextValue)
    }

    onChange?.(nextValue)
  }

  const fetchInfo = async () => {
    if (!normalizedTenantId) {
      return
    }

    const currentRequestId = requestIdRef.current + 1
    requestIdRef.current = currentRequestId

    setLoading(true)
    setCurError(undefined)

    try {
      const tenantData = (await getTenant(normalizedTenantId)).data

      if (currentRequestId !== requestIdRef.current) {
        return
      }

      setTenantInfo(tenantData)
      setLoadedTenantId(normalizedTenantId)
    } catch (error) {
      if (currentRequestId !== requestIdRef.current) {
        return
      }

      setTenantInfo(undefined)
      setCurError(getErrorMessage(error))
      setLoadedTenantId(normalizedTenantId)
    } finally {
      if (currentRequestId === requestIdRef.current) {
        setLoading(false)
      }
    }
  }

  useEffect(() => {
    if (!isPopoverOpen || disabled || !normalizedTenantId || loading) {
      return
    }

    if (loadedTenantId === normalizedTenantId) {
      return
    }

    fetchInfo()
  }, [
    disabled,
    fetchInfo,
    isPopoverOpen,
    loadedTenantId,
    loading,
    normalizedTenantId
  ])

  const handleOpenChange = (visible: boolean) => {
    setIsPopoverOpen(visible)
  }

  const renderPopoverContent = () => {
    if (curError) {
      return (
        <Alert
          message="Error"
          description={curError}
          type="error"
          showIcon
          style={{ width: '400px', marginBottom: '12px' }}
        />
      )
    }

    if (loading || !tenantInfo) {
      return (
        <div style={{ width: '400px', padding: '12px 0', textAlign: 'center' }}>
          <Spin />
        </div>
      )
    }

    return (
      <div style={{ width: '400px' }}>
        <Descriptions column={1} size="small">
          <Descriptions.Item label="Tenant">
            {tenantInfo.name} ({tenantInfo.id})
          </Descriptions.Item>
          <Descriptions.Item label="Region">
            {tenantInfo.region || '-'}
          </Descriptions.Item>
          <Descriptions.Item label="Status">
            {tenantInfo.status || '-'}
          </Descriptions.Item>
        </Descriptions>
      </div>
    )
  }

  return (
    <div className={className} style={{ display: 'flex', ...style }}>
      <Input
        value={inputValue}
        disabled={disabled}
        placeholder={placeholder}
        onChange={handleInputChange}
        style={{ borderRadius: '2px 0 0 2px' }}
      />
      <Popover
        content={renderPopoverContent()}
        trigger="hover"
        open={isPopoverOpen}
        onOpenChange={handleOpenChange}
        mouseEnterDelay={0.3}
      >
        <Button
          disabled={disabled || !normalizedTenantId}
          icon={<InfoCircleOutlined />}
          style={{ borderRadius: '0 2px 2px 0', marginLeft: '-1px' }}
        />
      </Popover>
    </div>
  )
}

export default TenantSearchInput
export { TenantSearchInput }
