package com.optix.android.domain.usecase

import com.optix.android.domain.repository.ToolRepository
import com.optix.android.tools.engine.EnvironmentManager
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow
import javax.inject.Inject

/**
 * One-time capability bootstrapping: checks root + Termux and installs the
 * Termux packages required by the enabled/registered tools that need them.
 *
 * Emits a sequence of [BootstrapStep] statuses so the UI can show progress
 * without blocking on the (potentially long) `pkg install` calls.
 */
class BootstrapCapabilities @Inject constructor(
    private val toolRepository: ToolRepository,
    private val environmentManager: EnvironmentManager,
) {
    operator fun invoke(): Flow<BootstrapStep> = flow {
        val termuxInstalled = environmentManager.isTermuxInstalled()
        val rootAvailable = environmentManager.isRootAvailable()

        emit(BootstrapStep.CapabilityCheck(termuxInstalled, rootAvailable))

        if (!termuxInstalled) {
            emit(
                BootstrapStep.TermuxMissing(
                    "Termux is not installed. Install it from F-Droid, then re-run setup " +
                        "to provision required packages."
                )
            )
            emit(BootstrapStep.Finished(emptyList(), termuxInstalled, rootAvailable))
            return@flow
        }

        // Collect the unique packages required by any Termux-aware tool.
        val requiredPackages = toolRepository.getAllTools()
            .filter { it.requiresTermux || it.requiredPackages.isNotEmpty() }
            .flatMap { it.requiredPackages.ifEmpty { listOf(it.name) } }
            .toSet()

        if (requiredPackages.isEmpty()) {
            emit(BootstrapStep.Finished(emptyList(), termuxInstalled, rootAvailable))
            return@flow
        }

        val results = mutableListOf<PackageResult>()
        requiredPackages.forEach { pkg ->
            emit(BootstrapStep.Installing(pkg))
            val ok = environmentManager.installTermuxPackage(pkg) { line ->
                // Forward install output to the UI as a log line.
                emit(BootstrapStep.Log("[$pkg] $line"))
            }
            val alreadyOk = ok && environmentManager.isBinaryAvailable(pkg)
            results.add(
                PackageResult(
                    packageName = pkg,
                    success = ok,
                    present = alreadyOk,
                )
            )
            emit(
                if (ok) BootstrapStep.PackageInstalled(pkg)
                else BootstrapStep.PackageFailed(pkg, "Install reported failure.")
            )
        }

        emit(BootstrapStep.Finished(results, termuxInstalled, rootAvailable))
    }
}

sealed class BootstrapStep {
    data class CapabilityCheck(val termuxInstalled: Boolean, val rootAvailable: Boolean) : BootstrapStep()
    data class TermuxMissing(val message: String) : BootstrapStep()
    data class Installing(val packageName: String) : BootstrapStep()
    data class PackageInstalled(val packageName: String) : BootstrapStep()
    data class PackageFailed(val packageName: String, val message: String) : BootstrapStep()
    data class Log(val message: String) : BootstrapStep()
    data class Finished(
        val results: List<PackageResult>,
        val termuxInstalled: Boolean,
        val rootAvailable: Boolean,
    ) : BootstrapStep()
}

data class PackageResult(
    val packageName: String,
    val success: Boolean,
    val present: Boolean,
)
