package expo.modules.filesystem.unifiedfile import android.net.Uri import android.os.Build import android.os.ParcelFileDescriptor import android.webkit.MimeTypeMap import androidx.core.content.FileProvider import androidx.core.net.toUri import expo.modules.filesystem.fsops.CopyMoveStrategy import expo.modules.kotlin.AppContext import java.io.File import java.io.FileInputStream import java.io.FileOutputStream import java.io.InputStream import java.io.OutputStream import java.net.URI import java.nio.file.attribute.BasicFileAttributes import kotlin.io.path.Path import kotlin.io.path.readAttributes import kotlin.time.Duration.Companion.milliseconds class JavaFile(override val uri: Uri) : UnifiedFileInterface, File(URI.create(uri.toString())) { override val parentFile: UnifiedFileInterface? get() = super.parentFile?.toUri()?.let { JavaFile(it) } override fun createFile(mimeType: String, displayName: String): UnifiedFileInterface? { val childFile = File(this, displayName) childFile.createNewFile() return JavaFile(childFile.toUri()) } override fun createDirectory(displayName: String): UnifiedFileInterface? { val childFile = File(this, displayName) childFile.mkdir() return JavaFile(childFile.toUri()) } override fun deleteRecursively(): Boolean { if (isDirectory) { listFiles()?.forEach { it.deleteRecursively() } } return super.delete() } override fun getContentUri(appContext: AppContext): Uri { return FileProvider.getUriForFile( appContext.throwingActivity.application, "${appContext.throwingActivity.application.packageName}.FileSystemFileProvider", this ) } override fun listFilesAsUnified(): List = super.listFiles()?.map { JavaFile(it.toUri()) } ?: emptyList() override val type: String? get() { return MimeTypeMap.getFileExtensionFromUrl(path) ?.run { MimeTypeMap.getSingleton().getMimeTypeFromExtension(lowercase()) } } override val fileName: String? get() = super.name override val creationTime: Long? get() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val attributes = Path(path).readAttributes() return attributes.creationTime().toMillis().milliseconds.inWholeMilliseconds } else { return null } } override fun outputStream(append: Boolean): OutputStream { return FileOutputStream(this, append) } override fun inputStream(): InputStream { return FileInputStream(this) } override fun openFileDescriptor(mode: String): ParcelFileDescriptor? = runCatching { val pfdMode = when (mode) { "r" -> ParcelFileDescriptor.MODE_READ_ONLY "w" -> ParcelFileDescriptor.MODE_WRITE_ONLY or ParcelFileDescriptor.MODE_CREATE or ParcelFileDescriptor.MODE_TRUNCATE else -> return null } ParcelFileDescriptor.open(this, pfdMode) }.getOrNull() override fun walkTopDown(): Sequence { return walk(direction = FileWalkDirection.TOP_DOWN).map { JavaFile(it.toUri()) } } override val copyMoveStrategy: CopyMoveStrategy = CopyMoveStrategy.LocalFile(this) }