import { useState, useCallback, useRef, useEffect } from 'react'
import { authService } from '@/services/common'
import { BizTypeEnum, FetchS3StsTokenResponse } from '@/services/common/types'

interface CachedToken {
  token: FetchS3StsTokenResponse
  expiresAt: number // 时间戳
  bizType: BizTypeEnum
}

interface UseS3TokenCacheOptions {
  preloadBizTypes?: BizTypeEnum[] // 预加载的业务类型
  refreshBeforeExpireMinutes?: number // 在过期前多少分钟刷新token，默认5分钟
}

interface UseS3TokenCacheReturn {
  getToken: (bizType: BizTypeEnum) => Promise<FetchS3StsTokenResponse>
  preloadTokens: (bizTypes: BizTypeEnum[]) => Promise<void>
  clearCache: () => void
  isTokenValid: (bizType: BizTypeEnum) => boolean
}

// 全局token缓存，跨组件共享
const tokenCache = new Map<BizTypeEnum, CachedToken>()

export function useS3TokenCache(options: UseS3TokenCacheOptions = {}): UseS3TokenCacheReturn {
  const { preloadBizTypes = [], refreshBeforeExpireMinutes = 5 } = options

  const [loading, setLoading] = useState(false)
  const refreshTimersRef = useRef<Map<BizTypeEnum, NodeJS.Timeout>>(new Map())

  // 检查token是否有效（未过期且在刷新时间内）
  const isTokenValid = useCallback(
    (bizType: BizTypeEnum): boolean => {
      const cached = tokenCache.get(bizType)
      if (!cached) return false

      const now = Date.now()
      const refreshThreshold = refreshBeforeExpireMinutes * 60 * 1000
      return cached.expiresAt - refreshThreshold > now
    },
    [refreshBeforeExpireMinutes]
  )

  // 获取新的token
  const fetchNewToken = useCallback(
    async (bizType: BizTypeEnum): Promise<FetchS3StsTokenResponse> => {
      try {
        console.log(`[S3TokenCache] 🌐 从API获取token for ${bizType}`)
        const response = await authService.fetchS3StsToken({
          bizTypeEnum: bizType,
        })

        // 计算过期时间（假设token有效期1小时）
        const expiresAt = Date.now() + 60 * 60 * 1000 // 1小时后过期

        // 缓存token
        const cachedToken: CachedToken = {
          token: response,
          expiresAt,
          bizType,
        }
        tokenCache.set(bizType, cachedToken)
        console.log(
          `[S3TokenCache] 💾 已缓存token for ${bizType}, 过期时间: ${new Date(expiresAt).toLocaleString()}`
        )

        // 设置自动刷新定时器 - 使用稳定的刷新函数避免递归
        const existingTimer = refreshTimersRef.current.get(bizType)
        if (existingTimer) {
          clearTimeout(existingTimer)
        }

        const refreshTime = expiresAt - refreshBeforeExpireMinutes * 60 * 1000 - Date.now()
        if (refreshTime > 0) {
          const timer = setTimeout(async () => {
            try {
              // 直接调用API，避免递归
              const refreshResponse = await authService.fetchS3StsToken({
                bizTypeEnum: bizType,
              })

              const newExpiresAt = Date.now() + 60 * 60 * 1000
              const newCachedToken: CachedToken = {
                token: refreshResponse,
                expiresAt: newExpiresAt,
                bizType,
              }
              tokenCache.set(bizType, newCachedToken)

              console.log(`Token refreshed for ${bizType}`)
            } catch (error) {
              console.error(`Failed to refresh token for ${bizType}:`, error)
            }
          }, refreshTime)

          refreshTimersRef.current.set(bizType, timer)
        }

        return response
      } catch (error) {
        console.error('Failed to fetch S3 token:', error)
        throw error
      }
    },
    [refreshBeforeExpireMinutes]
  )

  // 获取token（优先使用缓存）
  const getToken = useCallback(
    async (bizType: BizTypeEnum): Promise<FetchS3StsTokenResponse> => {
      console.log(`[S3TokenCache] 请求token for ${bizType}`)

      // 检查缓存是否有效
      if (isTokenValid(bizType)) {
        const cached = tokenCache.get(bizType)!
        console.log(`[S3TokenCache] ✅ 使用缓存token for ${bizType}`)
        return cached.token
      }

      // 缓存无效，获取新token
      console.log(`[S3TokenCache] 🔄 缓存失效，获取新token for ${bizType}`)
      return fetchNewToken(bizType)
    },
    [isTokenValid, fetchNewToken]
  )

  // 预加载多个业务类型的token
  const preloadTokens = useCallback(
    async (bizTypes: BizTypeEnum[]): Promise<void> => {
      setLoading(true)
      try {
        const promises = bizTypes.map(async (bizType) => {
          // 检查缓存是否有效
          const cached = tokenCache.get(bizType)
          if (!cached) {
            // 没有缓存，直接获取
            return fetchNewToken(bizType)
          }

          const now = Date.now()
          const refreshThreshold = refreshBeforeExpireMinutes * 60 * 1000
          const isValid = cached.expiresAt - refreshThreshold > now

          if (!isValid) {
            // 缓存无效，重新获取
            return fetchNewToken(bizType)
          }

          // 缓存有效，直接返回
          return Promise.resolve()
        })

        await Promise.all(promises)
      } catch (error) {
        console.error('Failed to preload tokens:', error)
      } finally {
        setLoading(false)
      }
    },
    [refreshBeforeExpireMinutes]
  ) // 移除其他依赖，避免循环

  // 清空缓存
  const clearCache = useCallback(() => {
    tokenCache.clear()

    // 清理所有定时器
    refreshTimersRef.current.forEach((timer) => clearTimeout(timer))
    refreshTimersRef.current.clear()
  }, [])

  // 组件挂载时预加载指定的token - 使用useRef避免依赖变化导致的重复调用
  const preloadBizTypesRef = useRef<BizTypeEnum[]>([])

  useEffect(() => {
    // 比较数组内容是否真正发生变化
    const hasChanged =
      preloadBizTypes.length !== preloadBizTypesRef.current.length ||
      preloadBizTypes.some((type, index) => type !== preloadBizTypesRef.current[index])

    if (hasChanged && preloadBizTypes.length > 0) {
      preloadBizTypesRef.current = [...preloadBizTypes]
      // 直接调用，避免依赖闭包
      const loadTokens = async () => {
        setLoading(true)
        try {
          const promises = preloadBizTypes.map(async (bizType) => {
            // 检查缓存是否有效
            const cached = tokenCache.get(bizType)
            if (!cached) {
              // 没有缓存，直接获取
              return fetchNewToken(bizType)
            }

            const now = Date.now()
            const refreshThreshold = refreshBeforeExpireMinutes * 60 * 1000
            const isValid = cached.expiresAt - refreshThreshold > now

            if (!isValid) {
              // 缓存无效，重新获取
              return fetchNewToken(bizType)
            }

            // 缓存有效，直接返回
            return Promise.resolve()
          })

          await Promise.all(promises)
        } catch (error) {
          console.error('Failed to preload tokens:', error)
        } finally {
          setLoading(false)
        }
      }

      loadTokens()
    }
  }, [preloadBizTypes, fetchNewToken, refreshBeforeExpireMinutes]) // 添加必要的依赖

  // 组件卸载时清理定时器
  useEffect(() => {
    return () => {
      refreshTimersRef.current.forEach((timer) => clearTimeout(timer))
      refreshTimersRef.current.clear()
    }
  }, [])

  return {
    getToken,
    preloadTokens,
    clearCache,
    isTokenValid,
  }
}

// 导出类型
export type { UseS3TokenCacheOptions, UseS3TokenCacheReturn }

/*
使用示例：

```tsx
import { useS3TokenCache } from '@/hooks/useS3TokenCache'
import { BizTypeEnum } from '@/services/common/types'

function ChatComponent() {
  // 在聊天界面预加载SOUND和IM类型的token
  const { getToken, preloadTokens } = useS3TokenCache({
    preloadBizTypes: [BizTypeEnum.SOUND, BizTypeEnum.IM],
    refreshBeforeExpireMinutes: 5
  })

  // 使用token
  const handleUpload = async () => {
    try {
      const token = await getToken(BizTypeEnum.SOUND, 'wav')
      // 使用token进行上传
    } catch (error) {
      console.error('获取token失败:', error)
    }
  }

  return <div>...</div>
}
```

功能特性：
1. ✅ Token缓存和自动过期管理
2. ✅ 自动刷新机制（在过期前刷新）
3. ✅ 预加载指定业务类型的token
4. ✅ 跨组件共享缓存
5. ✅ 内存清理和定时器管理
6. ✅ TypeScript 类型支持
7. ✅ 错误处理

配置选项：
- preloadBizTypes: 需要预加载的业务类型数组
- refreshBeforeExpireMinutes: 在过期前多少分钟自动刷新（默认5分钟）
*/
