/*
 * Copyright 2025 Signal Messenger, LLC
 * SPDX-License-Identifier: AGPL-3.0-only
 */

package org.signal.glide.common.io

import android.net.Uri
import com.bumptech.glide.load.engine.bitmap_recycle.ArrayPool
import com.bumptech.glide.load.resource.bitmap.RecyclableBufferedInputStream
import org.signal.core.util.logging.Log
import org.signal.glide.SignalGlideDependencies
import java.io.File
import java.io.FileInputStream
import java.io.InputStream

interface InputStreamFactory {
  companion object {
    @JvmStatic
    @JvmOverloads
    fun build(uri: Uri, thumbnailTimeUs: Long = 0): InputStreamFactory = SignalGlideDependencies.getUriInputStreamFactory(uri, thumbnailTimeUs)

    @JvmStatic
    fun build(file: File): InputStreamFactory = FileInputStreamFactory(file)
  }

  fun create(): InputStream
  fun createRecyclable(byteArrayPool: ArrayPool): InputStream = RecyclableBufferedInputStream(create(), byteArrayPool)

  /**
   * An upper bound on the number of bytes [create] will yield, if cheaply knowable, else null.
   */
  fun length(): Long? = null
}

/**
 * A factory that creates a new [InputStream] for the given [File] each time [create] is called.
 */
class FileInputStreamFactory(
  private val file: File
) : InputStreamFactory {
  companion object {
    private val TAG = Log.tag(FileInputStreamFactory::class)
  }

  override fun create(): InputStream {
    return try {
      FileInputStream(file)
    } catch (e: Exception) {
      Log.w(TAG, "Error creating input stream for File.", e)
      throw e
    }
  }

  override fun length(): Long? = file.length().takeIf { it > 0 }
}
