package com.correx.apps.server.workspace

import com.correx.core.kernel.orchestration.WorkspaceContext
import com.correx.infrastructure.tools.filesystem.PathJail
import java.nio.file.Files
import java.nio.file.Path

sealed interface WorkspaceResolution {
    data class Bound(val workspace: WorkspaceContext) : WorkspaceResolution
    data class Rejected(val reason: String, val fallback: WorkspaceContext) : WorkspaceResolution
}

class WorkspaceResolver(
    private val bootDefault: WorkspaceContext,
    private val privilegedLocations: List<Path>,
    private val allowedWorkspaceRoots: List<Path>,
) {
    fun resolve(clientDir: String?): WorkspaceResolution {
        clientDir ?: return WorkspaceResolution.Bound(bootDefault)

        val canonical = runCatching { Path.of(clientDir).toRealPath() }
            .getOrElse {
                return WorkspaceResolution.Rejected(
                    "workspace path does not exist or is not accessible: $clientDir",
                    bootDefault,
                )
            }

        if (!Files.isDirectory(canonical)) {
            return WorkspaceResolution.Rejected(
                "workspace path is not a directory: $canonical",
                bootDefault,
            )
        }

        val isPrivileged = privilegedLocations.any { priv ->
            val realPriv = runCatching { priv.toRealPath() }.getOrDefault(priv)
            canonical.startsWith(realPriv)
        }
        if (isPrivileged) {
            return WorkspaceResolution.Rejected(
                "workspace path is a privileged location: $canonical",
                bootDefault,
            )
        }

        if (allowedWorkspaceRoots.isNotEmpty()) {
            val contained = PathJail.isContained(canonical, allowedWorkspaceRoots.toSet())
            if (!contained) {
                return WorkspaceResolution.Rejected(
                    "workspace path not under an allowed root: $canonical",
                    bootDefault,
                )
            }
        }

        return WorkspaceResolution.Bound(
            WorkspaceContext(
                workspaceRoot = canonical,
                workingDir = canonical,
                allowedPaths = setOf(canonical),
                privilegedLocations = privilegedLocations,
            )
        )
    }
}
