// Copyright (C) 2026 Jason M. Schwefel. All Rights Reserved.
package com.coldboreballisticsllc.scopedope.data.session

import android.content.Context
import android.net.Uri
import android.provider.OpenableColumns
import dagger.hilt.android.qualifiers.ApplicationContext
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton

sealed class ImportResult {
    data class Success(val file: File)          : ImportResult()
    data class Duplicate(val uri: Uri, val filename: String) : ImportResult()
    data class Failure(val message: String)     : ImportResult()
}

/**
 * Manages the app-private ScopeDOPE session library at
 * getExternalFilesDir("ScopeDOPE"). No storage permissions required.
 * Visible via USB at Android/data/com.coldboreballisticsllc.scopedope/files/ScopeDOPE/.
 */
@Singleton
class ScopeDOPEFileManager @Inject constructor(
    @ApplicationContext private val context: Context,
) {
    private val _directory: File by lazy {
        File(context.getExternalFilesDir(null), "ScopeDOPE").also { it.mkdirs() }
    }
    val directory: File get() = _directory

    val displayPath: String by lazy {
        "Android/data/${context.packageName}/files/ScopeDOPE"
    }

    fun list(dopeOnly: Boolean = true): List<File> =
        (directory.listFiles() ?: emptyArray())
            .filter { it.isFile && (!dopeOnly || it.extension.equals("dope", ignoreCase = true)) }
            .sortedByDescending { it.lastModified() }

    fun resolveFilename(uri: Uri): String {
        context.contentResolver.query(uri, null, null, null, null)?.use { cursor ->
            if (cursor.moveToFirst()) {
                val idx = cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME)
                if (idx >= 0) return cursor.getString(idx)
            }
        }
        return uri.lastPathSegment?.substringAfterLast('/') ?: "session.dope"
    }

    fun importUri(uri: Uri, filename: String): ImportResult {
        if (File(directory, filename).exists()) return ImportResult.Duplicate(uri, filename)
        return writeUri(uri, filename)
    }

    fun overwrite(uri: Uri, filename: String): ImportResult = writeUri(uri, filename)

    fun keepBoth(uri: Uri, filename: String): ImportResult {
        val base = filename.substringBeforeLast(".")
        val ext  = filename.substringAfterLast(".", "dope")
        var n = 1
        var dest: File
        do { dest = File(directory, "$base ($n).$ext"); n++ } while (dest.exists() && n <= 99)
        if (n > 99) return ImportResult.Failure("Too many versions of '$filename'")
        return writeUri(uri, dest.name)
    }

    private fun writeUri(uri: Uri, filename: String): ImportResult = runCatching {
        val safeName = File(filename).name   // strip any path components before writing
        val dest = File(directory, safeName)
        check(dest.canonicalFile.parentFile?.canonicalPath == directory.canonicalFile.canonicalPath) {
            "Path traversal rejected"
        }
        context.contentResolver.openInputStream(uri)?.use { it.copyTo(dest.outputStream()) }
            ?: error("Cannot read $uri")
        ImportResult.Success(dest)
    }.getOrElse { ImportResult.Failure(it.message ?: "Unknown error") }
}
