import type OSS from 'ali-oss'
import {
  getSTSToken,
  getOssSignatureUrl,
  checkOssSignatureUrlIsExist,
} from '@apis/oss'
import type { STSTokenResponse, UploadParams, UploadResult } from '../type'
import { OSSBucketType } from '../type'
import { StorageAdapter } from './base'

// 常量定义
const OSS_REGION = 'oss-cn-hangzhou'

export class OSSClient extends StorageAdapter<OSS> {
  private static instance: OSSClient

  // 获取默认实例键值
  protected getDefaultInstanceKey(): string {
    return 'bty-oss-token'
  }

  // 获取提供商前缀
  protected getProviderPrefix(): string {
    return 'custom-oss'
  }

  // 默认获取STS Token的方法
  protected async defaultGetSTSToken(): Promise<STSTokenResponse> {
    return getSTSToken()
  }

  // 获取默认OSSClient单例
  public static getInstance(): OSSClient {
    if (!OSSClient.instance) {
      OSSClient.instance = new OSSClient()
    }
    return OSSClient.instance
  }

  // 创建自定义OSSClient实例
  public static createCustomInstance(
    getSTSTokenFn: () => Promise<STSTokenResponse>,
  ): OSSClient {
    return new OSSClient(getSTSTokenFn)
  }

  // 刷新OSS客户端
  protected async refreshClient(): Promise<void> {
    const token = await this.getSTSToken()
    const aliOssModule: any = await import('ali-oss')
    const OSSSdk: typeof OSS = aliOssModule.default || (aliOssModule as any)
    this.client = new OSSSdk({
      region: token.region || OSS_REGION,
      accessKeyId: token.access_key_id,
      accessKeySecret: token.access_key_secret,
      stsToken: token.security_token,
      secure: true,
      ...(Reflect.has(token, 'secure') ? { secure: token.secure } : {}),
    })
    this.bucketMap = {
      [OSSBucketType.PRIVATE]: token.data_bucket,
      [OSSBucketType.PUBLIC]: token.resource_bucket,
    } as Record<OSSBucketType, string>
  }

  // 上传文件
  public async upload(params: UploadParams): Promise<UploadResult> {
    try {
      const client = await this.getClient()
      const bucketName =
        params.custom_bucket ||
        this.getBucketName(params.bucketType || OSSBucketType.PRIVATE)
      client!.useBucket(bucketName)

      const result = await client.put(
        params.filePath,
        params.file,
        params.options || {},
      )
      const url = (result.res as any)?.requestUrls?.[0]?.split('?')?.[0]
      return { url, result }
    } catch (error) {
      console.error('File upload failed:', error)
      throw new Error(`File upload failed: ${(error as Error).message}`)
    }
  }

  public async multipartUpload(params: UploadParams): Promise<UploadResult> {
    try {
      const client = await this.getClient()
      const bucketName =
        params.custom_bucket ||
        this.getBucketName(params.bucketType || OSSBucketType.PRIVATE)
      client!.useBucket(bucketName)
      const result = await client.multipartUpload(
        params.filePath,
        params.file,
        params.options || {},
      )
      const url = (result.res as any)?.requestUrls?.[0]?.split('?')?.[0]
      return { url, result }
    } catch (error) {
      console.error('File upload failed:', error)
      throw new Error(`File upload failed: ${(error as Error).message}`)
    }
  }

  public async getOssSignatureUrl(key: string, params?: Record<string, any>) {
    return getOssSignatureUrl(key, params)
  }

  public async checkOssSignatureUrlIsExist(url: string) {
    return checkOssSignatureUrlIsExist(url)
  }
}
