package solutions.tretter.githugandroid

import java.io.File

/**
 * Port of the upstream ruby-githug `push` level.
 *
 * Setup documents the repository shape the learner explores. Evaluation is kept
 * state-based whenever the exercise changes repository objects; answer-only
 * levels intentionally validate the answer entered at the prompt.
 */
internal fun pushLevel(): Level = level(
    id = "push",
    title = "Push",
    description = "Your local master branch has diverged from the remote origin/master branch. Rebase your branch onto origin/master and push it to remote.",
    hints = listOf("Take a look at `git fetch`, `git pull`, and `git push`."),
    commandSuggestions = listOf("git pull --rebase origin master", "git push origin master"),
    setup = {
        RepoState(
            initialized = true,
            files = listOf(
                GitFile("file1", tracked = true),
                GitFile("file2", tracked = true),
                GitFile("file3", tracked = true),
            ),
            commits = listOf(
                CommitNode("0000001", "First commit"),
                CommitNode("0000002", "Second commit"),
                CommitNode("0000003", "Third commit"),
            ),
            remotes = mapOf("origin" to "remote"),
            branches = mapOf("master" to 3),
            fetchedBranches = setOf("origin/master"),
        )
    },
    nativeSetup = {
        resetFiles()
        write("file1", "file1\n")
        addCommit("First commit", "file1")
        write("file2", "file2\n")
        addCommit("Second commit", "file2")

        val parent = sandbox.parentFile ?: sandbox
        val remoteDir = File(parent, "${sandbox.name}-origin.git")
        val remoteWorkTree = File(parent, "${sandbox.name}-origin-work")
        remoteDir.deleteRecursively()
        remoteWorkTree.deleteRecursively()
        remoteDir.mkdirs()
        remoteWorkTree.mkdirs()
        git(remoteDir, "init", "--bare", "-b", "master")
        git("remote", "add", "push-setup-origin", remoteDir.absolutePath)
        git("push", "push-setup-origin", "master")
        git("remote", "remove", "push-setup-origin")

        fun remoteGit(vararg arguments: String) {
            git(
                "--git-dir",
                remoteDir.absolutePath,
                "--work-tree",
                remoteWorkTree.absolutePath,
                *arguments,
            )
        }

        remoteGit("checkout", "-f", "master")
        File(remoteWorkTree, "file4").writeText("file4\n")
        remoteGit("add", "file4")
        remoteGit("commit", "-m", "Fourth commit")

        write("file3", "file3\n")
        addCommit("Third commit", "file3")
        git("remote", "add", "origin", remoteDir.absolutePath)
        git("fetch", "origin")
        git("branch", "--set-upstream-to=origin/master", "master")
        git("config", "rebase.autoStash", "true")
        append("file3", "local worktree change\n")
        true
    },
    validator = repoPredicate { repo ->
        "origin/master" in repo.pushedBranches &&
            repo.commits.size >= 4 &&
            listOf("file1", "file2", "file3", "file4").all { expected ->
                repo.files.any { file -> file.name == expected && file.tracked && !file.deleted }
            }
    },
    testCases = listOf(
        levelTestCase("pull rebase then push", "git pull --rebase origin master", "git push origin master"),
        levelTestCase("fetch rebase push", "git fetch origin", "git rebase origin/master", "git push origin master"),
    ),
)
