import OssSingleton from '../OssSingleton'
import type {
  STSTokenResponse,
  OSSBucketType,
  UploadParams,
  UploadResult,
} from '../type'

// 常量定义
// 最大缓存时长：无论 token 实际有效期多久，最多只缓存 10 分钟
export const MAX_TOKEN_CACHE_DURATION = 10 * 60 * 1000 // 10 分钟

/**
 * 根据 token 的 expiration 字段计算缓存时长
 * @param tokenResponse STS Token 响应
 * @returns 缓存时长（毫秒）
 */
export function calculateTokenCacheDuration(
  tokenResponse: STSTokenResponse,
): number {
  // 如果没有 expiration 字段，使用最大缓存时长
  if (!tokenResponse.expiration) {
    return MAX_TOKEN_CACHE_DURATION
  }

  try {
    const expirationTime = new Date(tokenResponse.expiration).getTime()
    const remainingTime = expirationTime - Date.now()

    // token 已过期，不缓存
    if (remainingTime <= 0) {
      return 0
    }

    // 取服务端返回的时间和最大缓存时长中的较小值
    const cacheDuration = Math.min(remainingTime, MAX_TOKEN_CACHE_DURATION)

    console.log('[Token Cache] Cache duration:', cacheDuration, 'ms')
    return cacheDuration
  } catch (error) {
    console.warn('[Token Cache] Parse error, using max duration:', error)
    return MAX_TOKEN_CACHE_DURATION
  }
}

// 存储适配器抽象基类
export abstract class StorageAdapter<C = any> {
  protected client: C | null = null
  protected instanceKey: string | null = null
  protected bucketMap: Record<OSSBucketType, string> = {} as Record<
    OSSBucketType,
    string
  >

  protected getSTSTokenFn: () => Promise<STSTokenResponse>

  constructor(getSTSTokenFn?: () => Promise<STSTokenResponse>) {
    if (getSTSTokenFn) {
      this.getSTSTokenFn = getSTSTokenFn
      this.instanceKey = this.generateInstanceKey(getSTSTokenFn)
    } else {
      this.getSTSTokenFn = this.defaultGetSTSToken
      this.instanceKey = this.getDefaultInstanceKey()
    }
  }

  // 生成实例唯一键值
  protected generateInstanceKey(fn: (...args: any[]) => any): string {
    const fnString = fn.toString()
    let hash = 0
    for (let i = 0; i < fnString.length; i++) {
      const char = fnString.charCodeAt(i)
      hash = (hash << 5) - hash + char
      hash = hash & hash
    }
    return `${this.getProviderPrefix()}-token-${hash}`
  }

  // 获取默认实例键值
  protected abstract getDefaultInstanceKey(): string

  // 获取提供商前缀
  protected abstract getProviderPrefix(): string

  // 默认获取STS Token的方法
  protected abstract defaultGetSTSToken(): Promise<STSTokenResponse>

  // 获取并可能刷新STS Token
  protected async getSTSToken(): Promise<STSTokenResponse> {
    return OssSingleton.getCachedData<STSTokenResponse>(
      this.instanceKey!,
      this.getSTSTokenFn,
      // 传入函数来动态计算缓存时长
      calculateTokenCacheDuration,
    )
  }

  // 刷新客户端
  protected abstract refreshClient(): Promise<void>

  // 获取客户端
  public async getClient(): Promise<C> {
    // 检查 token 缓存是否过期
    const tokenExpired = OssSingleton.isCacheExpired(this.instanceKey!)

    // 如果 client 不存在或 token 已过期，则刷新 client
    if (!this.client || tokenExpired) {
      console.log('[Client] Refreshing client, token expired:', tokenExpired)
      await this.refreshClient()
    }

    return this.client!
  }

  // 获取存储桶名称
  protected getBucketName(bucketType: OSSBucketType): string {
    return this.bucketMap[bucketType]
  }

  // 抽象方法，子类必须实现
  public abstract upload(params: UploadParams): Promise<UploadResult>
  public abstract multipartUpload(params: UploadParams): Promise<UploadResult>
  public abstract getOssSignatureUrl(
    key: string,
    params?: Record<string, any>,
  ): Promise<string>
  public abstract checkOssSignatureUrlIsExist(url: string): Promise<boolean>
}
