import { S3Client, PutObjectCommand } from '@aws-sdk/client-s3'
import type { StorageProvider, StorageUploadOptions } from './types'

/**
 * Fly.io (Tigris) S3-compatible storage provider implementation
 */
export class FlyIoStorage implements StorageProvider {
  private client: S3Client
  private bucketName: string
  private endpoint: string
  private publicUrlBase?: string

  constructor(config: {
    accessKeyId: string
    secretAccessKey: string
    endpoint: string
    region: string
    bucketName: string
    publicUrlBase?: string
  }) {
    if (!config.accessKeyId || !config.secretAccessKey || !config.endpoint || !config.bucketName) {
      throw new Error('Fly.io storage configuration is incomplete')
    }

    this.bucketName = config.bucketName
    this.endpoint = config.endpoint
    this.publicUrlBase = config.publicUrlBase

    this.client = new S3Client({
      region: config.region || 'auto',
      endpoint: config.endpoint,
      credentials: {
        accessKeyId: config.accessKeyId,
        secretAccessKey: config.secretAccessKey
      },
      forcePathStyle: true // Required for S3-compatible services
    })
  }

  async upload(key: string, blob: Blob, options?: StorageUploadOptions): Promise<string> {
    const arrayBuffer = await blob.arrayBuffer()
    const buffer = Buffer.from(arrayBuffer)

    const command = new PutObjectCommand({
      Bucket: this.bucketName,
      Key: key,
      Body: buffer,
      ContentType: options?.contentType || blob.type || 'application/octet-stream',
      ACL: options?.access === 'public' ? 'public-read' : 'private'
    })

    try {
      await this.client.send(command)
    } catch (error: unknown) {
      const errorMessage = error instanceof Error ? error.message : String(error)
      // Provide more context in error message
      throw new Error(
        `Fly.io storage upload failed: ${errorMessage}. `
        + `Bucket: ${this.bucketName}, Endpoint: ${this.endpoint}. `
        + `Please verify the bucket exists and the credentials have access to it.`
      )
    }

    // Construct public URL
    // If publicUrlBase is provided, use it
    if (this.publicUrlBase) {
      return `${this.publicUrlBase.replace(/\/$/, '')}/${key}`
    }

    // For Fly.io Tigris, public buckets are accessible at:
    // https://{bucket-name}.fly.storage.tigris.dev/{key}
    // Fallback: construct URL from bucket name (assuming public bucket)
    return `https://${this.bucketName}.fly.storage.tigris.dev/${key}`
  }
}
