import Foundation

@testable import NucleicCore

/// A throwaway git repo under a temp dir, with deterministic identity, for the
/// WorktreeManager component tests (OBSERVABILITY: "real temp git repos"). Created
/// outside the iCloud tree (`NSTemporaryDirectory`) so it never trips the
/// provenance-xattr codesign issue and stays fast.
struct GitTestRepo {
    let root: String
    let git: GitRunner
    /// Parent of `root`; the default worktree base lands a sibling here.
    let container: String

    /// When `controlled` is true the repo is created under the Nucleic Control base
    /// (`~/.nucleic/control/`) so `Project.isNucleicControlled` is true — needed by tests that
    /// exercise Control-gated features (autoship, the managed sandbox). A unique UUID subdir
    /// keeps it isolated, and `cleanup()` removes it. Otherwise it lands under the temp dir.
    init(defaultBranch: String = "main", controlled: Bool = false) async throws {
        git = GitRunner()
        let parent = controlled ? ProjectCloner.controlBase : NSTemporaryDirectory()
        container = (parent as NSString)
            .appendingPathComponent("nucleic-tests-\(UUID().uuidString)")
        root = (container as NSString).appendingPathComponent("repo")
        try FileManager.default.createDirectory(atPath: root, withIntermediateDirectories: true)

        try await git.checked(["init", "-b", defaultBranch], in: root)
        try await git.checked(["config", "user.name", "Nucleic Test"], in: root)
        try await git.checked(["config", "user.email", "test@nucleic.invalid"], in: root)
        try await git.checked(["config", "commit.gpgsign", "false"], in: root)
        // Seed an initial commit so there's a base to branch from.
        try write("README.md", "# test repo\n")
        try await git.checked(["add", "-A"], in: root)
        try await git.checked(["commit", "-m", "initial"], in: root)
    }

    func project(name: String = "test", defaultBranch: GitRef = "main") -> Project {
        Project(name: name, rootPath: root, defaultBranch: defaultBranch)
    }

    /// Writes a file (relative to a worktree path, or repo root by default).
    func write(_ relative: String, _ contents: String, in base: String? = nil) throws {
        let dir = base ?? root
        let path = (dir as NSString).appendingPathComponent(relative)
        try FileManager.default.createDirectory(
            atPath: (path as NSString).deletingLastPathComponent, withIntermediateDirectories: true)
        try contents.write(toFile: path, atomically: true, encoding: .utf8)
    }

    func read(_ relative: String, in base: String? = nil) -> String? {
        let dir = base ?? root
        let path = (dir as NSString).appendingPathComponent(relative)
        return try? String(contentsOfFile: path, encoding: .utf8)
    }

    @discardableResult
    func run(_ args: [String], in cwd: String? = nil) async throws -> GitCommandResult {
        try await git.run(args, in: cwd ?? root)
    }

    func revParse(_ ref: String, in cwd: String? = nil) async throws -> String {
        try await git.checked(["rev-parse", ref], in: cwd ?? root)
    }

    func cleanup() {
        try? FileManager.default.removeItem(atPath: container)
    }
}
