import Testing
import Foundation
@testable import Alas

struct EnvBuilderTests {
    @Test func injectsAlasVars() {
        let project = ProjectConfig(id: "p", name: "owner/repo", path: "/tmp/repo",
                                    color: "#000", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "main", branch: "main",
                          path: URL(fileURLWithPath: "/tmp/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(project: project, worktree: wt, sessionId: "s-1",
                                   socketPath: "/tmp/alas.sock",
                                   inheritParent: false, parent: ["PATH": "/x"])
        #expect(env["ALAS_REPO"] == "owner/repo")
        #expect(env["ALAS_BRANCH"] == "main")
        #expect(env["ALAS_WORKTREE"] == "/tmp/wt")
        #expect(env["ALAS_SESSION_ID"] == "s-1")
        #expect(env["ALAS_SOCKET_PATH"] == "/tmp/alas.sock")
        #expect(env["PATH"] == nil)
    }

    @Test func mergesParentWhenInherit() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(project: project, worktree: wt, sessionId: "s",
                                   socketPath: nil,
                                   inheritParent: true, parent: ["PATH": "/x", "HOME": "/h"])
        #expect(env["PATH"] == "/x")
        #expect(env["HOME"] == "/h")
        #expect(env["ALAS_REPO"] == "x/y")
    }

    /// Codex review (#102): inherited ALAS_SOCKET_PATH must be stripped when
    /// we have no socket of our own, otherwise hooks installed in this new
    /// session would dispatch events to a stale/parent Alas instance and
    /// drive false state there.
    @Test func stripsInheritedSocketPathWhenNoServerAvailable() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "s",
            socketPath: nil,
            inheritParent: true,
            parent: ["ALAS_SOCKET_PATH": "/tmp/some-other-alas.sock"]
        )
        #expect(env["ALAS_SOCKET_PATH"] == nil)
    }

    @Test func ownSocketPathOverridesInheritedOne() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "s",
            socketPath: "/tmp/ours.sock",
            inheritParent: true,
            parent: ["ALAS_SOCKET_PATH": "/tmp/some-other-alas.sock"]
        )
        #expect(env["ALAS_SOCKET_PATH"] == "/tmp/ours.sock")
    }

    @Test func stripsTerminalVarsFromInheritedParent() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "s",
            socketPath: nil,
            inheritParent: true,
            parent: [
                "PATH": "/x",
                "TERM": "dumb",
                "TERM_PROGRAM": "MyIDE",
                "COLORTERM": "truecolor",
                "TERMINFO": "/some/path",
            ]
        )
        #expect(env["PATH"] == "/x")
        #expect(env["TERM"] == nil)
        #expect(env["TERM_PROGRAM"] == nil)
        #expect(env["COLORTERM"] == nil)
        #expect(env["TERMINFO"] == nil)
    }

    /// zmx injects ZMX_SESSION into the shells it spawns. If Alas inherits
    /// that env and forwards it into a freshly-spawned pane, any later
    /// `zmx attach <other>` from that shell silently hits zmx's switchSesh
    /// path and re-binds the pane to a different daemon's session, leaving
    /// one Alas tab piped into another tab's shell. See zmx#151.
    /// `ZMX_SESSION_PREFIX` is left intact so user-configured prefixes flow
    /// through to both the spawned shell and Alas's own zmx CLI calls.
    @Test func stripsZmxSessionButKeepsPrefixFromInheritedParent() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "s",
            socketPath: nil,
            inheritParent: true,
            parent: [
                "PATH": "/x",
                "ZMX_SESSION": "alas-foo",
                "ZMX_SESSION_PREFIX": "team-",
            ]
        )
        #expect(env["PATH"] == "/x")
        #expect(env["ZMX_SESSION"] == nil)
        #expect(env["ZMX_SESSION_PREFIX"] == "team-")
    }

    @Test func zmxDirIsEmittedWhenProvided() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "s",
            socketPath: nil,
            inheritParent: false,
            parent: [:],
            zmxDir: "/tmp/alas-zmx-501"
        )
        #expect(env["ZMX_DIR"] == "/tmp/alas-zmx-501")
    }

    @Test func zmxDirIsAbsentWhenNotProvided() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "s",
            socketPath: nil,
            inheritParent: false,
            parent: [:],
            zmxDir: nil
        )
        #expect(env["ZMX_DIR"] == nil)
    }

    @Test func alasSessionIdEqualsCallerSuppliedValue() {
        let project = ProjectConfig(id: "p", name: "x/y", path: "/r", color: "#0", addedAt: Date())
        let wt = Worktree(id: "w", projectId: "p", name: "m", branch: "m",
                          path: URL(fileURLWithPath: "/wt"),
                          status: .clean, lastActivity: Date())
        let env = EnvBuilder.build(
            project: project, worktree: wt, sessionId: "leaf-UUID-ABC",
            socketPath: nil,
            inheritParent: false,
            parent: [:],
            zmxDir: nil
        )
        #expect(env["ALAS_SESSION_ID"] == "leaf-UUID-ABC")
    }
}
