import { Alert, Descriptions, Spin } from 'antd'
import React, { useEffect, useRef, useState } from 'react'

import {
  getResourcePool,
  getSharedResourcePool,
  getTenant
} from 'apiClient/services/devops'
import {
  ClusterGetClusterResp,
  TenantGetTenantResp
} from 'apiClient/services/devops/interface'

import { getTenantLabel, shouldLoadTenant } from './shared'

export interface ResourcePoolDescriptionProps {
  resourcePoolId: string
  onLoaded?: (
    resourcePoolInfo: ClusterGetClusterResp,
    tenantInfo?: TenantGetTenantResp
  ) => void
}

const DEFAULT_ERROR_MESSAGE = 'Failed to fetch resource pool detail.'

function shouldFallbackToGenericResourcePool(error: unknown) {
  const axiosLikeError = error as {
    response?: { status?: number }
  }
  const status = axiosLikeError?.response?.status

  return status === 404 || status === 405
}

const getResourcePoolDetail = async (resourcePoolId: string) => {
  try {
    return await getSharedResourcePool(resourcePoolId)
  } catch (error) {
    if (!shouldFallbackToGenericResourcePool(error)) {
      throw error
    }

    return getResourcePool(resourcePoolId)
  }
}

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

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

export const ResourcePoolDescription: React.FC<
  ResourcePoolDescriptionProps
> = ({ resourcePoolId, onLoaded }) => {
  const [resourcePoolInfo, setResourcePoolInfo] =
    useState<ClusterGetClusterResp>()
  const [tenantInfo, setTenantInfo] = useState<TenantGetTenantResp>()
  const [curError, setCurError] = useState<string>()
  const [loading, setLoading] = useState(false)
  const requestIdRef = useRef(0)

  useEffect(() => {
    if (!resourcePoolId) {
      setResourcePoolInfo(undefined)
      setTenantInfo(undefined)
      setCurError(undefined)
      setLoading(false)
      return
    }

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

    const fetchInfo = async () => {
      setLoading(true)
      setCurError(undefined)
      setResourcePoolInfo(undefined)
      setTenantInfo(undefined)

      try {
        const resourcePoolData = (await getResourcePoolDetail(resourcePoolId))
          .data

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

        setResourcePoolInfo(resourcePoolData)

        let tenantData: TenantGetTenantResp | undefined
        if (shouldLoadTenant(resourcePoolData.tenant_id)) {
          tenantData = (await getTenant(resourcePoolData.tenant_id)).data

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

          setTenantInfo(tenantData)
        }

        onLoaded?.(resourcePoolData, tenantData)
      } catch (error) {
        if (currentRequestId !== requestIdRef.current) {
          return
        }

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

    fetchInfo()
  }, [resourcePoolId, onLoaded])

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

  if (loading || !resourcePoolInfo) {
    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="Resource Pool">
          {resourcePoolInfo.name} ({resourcePoolInfo.id})
        </Descriptions.Item>
        <Descriptions.Item label="Region">
          {resourcePoolInfo.region || '-'}
        </Descriptions.Item>
        <Descriptions.Item label="Logical Region">
          {resourcePoolInfo.logical_region || '-'}
        </Descriptions.Item>
        <Descriptions.Item label="Tenant">
          {getTenantLabel(resourcePoolInfo.tenant_id, tenantInfo)}
        </Descriptions.Item>
      </Descriptions>
    </div>
  )
}

export default ResourcePoolDescription
