-- SPDX-FileCopyrightText: Amolith <amolith@secluded.site>
--
-- SPDX-License-Identifier: GPL-3.0-or-later

package.path = package.path .. ";./?.lua"
local wt = dofile("src/main.lua")
local helper = require("spec.test_helper")
local git = helper.git

describe("find_project_root", function()
	local temp_dir

	setup(function()
		local handle = io.popen("mktemp -d")
		if handle then
			temp_dir = handle:read("*l")
			handle:close()
		end
	end)

	teardown(function()
		if temp_dir then
			os.execute("rm -rf " .. temp_dir)
		end
	end)

	describe("wt-managed repository (.bare + .git file)", function()
		it("finds root when cwd is project root", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/project"
			os.execute("mkdir -p " .. project .. "/.bare")
			git("init --bare " .. project .. "/.bare")
			local f = io.open(project .. "/.git", "w")
			if f then
				f:write("gitdir: ./.bare\n")
				f:close()
			end

			local root, err = wt.find_project_root(project)
			assert.is_nil(err)
			assert.are.equal(project, root)
		end)

		it("finds root when cwd is inside worktree", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/project2"
			os.execute("mkdir -p " .. project .. "/.bare")
			git("init --bare " .. project .. "/.bare")
			local f = io.open(project .. "/.git", "w")
			if f then
				f:write("gitdir: ./.bare\n")
				f:close()
			end

			os.execute("mkdir -p " .. project .. "/main/src/lib")
			local wt_git = io.open(project .. "/main/.git", "w")
			if wt_git then
				wt_git:write("gitdir: ../.bare/worktrees/main\n")
				wt_git:close()
			end

			local root, err = wt.find_project_root(project .. "/main/src/lib")
			assert.is_nil(err)
			assert.are.equal(project, root)
		end)

		it("finds root when cwd is in nested branch worktree", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/nested-wt"
			os.execute("mkdir -p " .. project .. "/.bare")
			git("init --bare " .. project .. "/.bare")
			local f = io.open(project .. "/.git", "w")
			if f then
				f:write("gitdir: ./.bare\n")
				f:close()
			end

			os.execute("mkdir -p " .. project .. "/feature/auth/src")
			local wt_git = io.open(project .. "/feature/auth/.git", "w")
			if wt_git then
				wt_git:write("gitdir: ../../.bare/worktrees/feature-auth\n")
				wt_git:close()
			end

			local root, err = wt.find_project_root(project .. "/feature/auth/src")
			assert.is_nil(err)
			assert.are.equal(project, root)
		end)
	end)

	describe("non-wt repository", function()
		it("returns error for normal git repo", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/normal-git"
			os.execute("mkdir -p " .. project)
			git("init " .. project)

			local root, err = wt.find_project_root(project)
			assert.is_nil(root)
			assert.is_not_nil(err)
			assert.is_truthy(err:match("not in a wt%-managed repository"))
		end)

		it("returns error for non-git directory", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/not-git"
			os.execute("mkdir -p " .. project)

			local root, err = wt.find_project_root(project)
			assert.is_nil(root)
			assert.is_not_nil(err)
		end)
	end)

	describe("edge cases", function()
		it("finds root with .bare but relative .git reference", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/rel-git"
			os.execute("mkdir -p " .. project .. "/.bare")
			git("init --bare " .. project .. "/.bare")

			local f = io.open(project .. "/.git", "w")
			if f then
				f:write("gitdir: .bare\n")
				f:close()
			end

			local root, err = wt.find_project_root(project)
			assert.is_nil(err)
			assert.are.equal(project, root)
		end)
	end)
end)

describe("detect_source_worktree", function()
	local temp_dir

	setup(function()
		local handle = io.popen("mktemp -d")
		if handle then
			temp_dir = handle:read("*l")
			handle:close()
		end
	end)

	teardown(function()
		if temp_dir then
			os.execute("rm -rf " .. temp_dir)
		end
	end)

	describe("at project root", function()
		it("returns nil when cwd equals root", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/proj1"
			os.execute("mkdir -p " .. project .. "/.bare")

			local result = wt.detect_source_worktree(project, project)
			assert.is_nil(result)
		end)
	end)

	describe("inside a worktree", function()
		it("returns worktree path when cwd has .git file", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/proj2"
			local worktree = project .. "/main"
			os.execute("mkdir -p " .. project .. "/.bare")
			os.execute("mkdir -p " .. worktree .. "/src")

			local f = io.open(worktree .. "/.git", "w")
			if f then
				f:write("gitdir: ../.bare/worktrees/main\n")
				f:close()
			end

			local result = wt.detect_source_worktree(project, worktree)
			assert.are.equal(worktree, result)
		end)

		it("finds worktree root when cwd is deep inside worktree", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/proj3"
			local worktree = project .. "/main"
			local deep_path = worktree .. "/src/lib/utils"
			os.execute("mkdir -p " .. project .. "/.bare")
			os.execute("mkdir -p " .. deep_path)

			local f = io.open(worktree .. "/.git", "w")
			if f then
				f:write("gitdir: ../.bare/worktrees/main\n")
				f:close()
			end

			local result = wt.detect_source_worktree(project, deep_path)
			assert.are.equal(worktree, result)
		end)

		it("finds nested branch worktree", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/proj4"
			local worktree = project .. "/feature/auth"
			os.execute("mkdir -p " .. project .. "/.bare")
			os.execute("mkdir -p " .. worktree .. "/src")

			local f = io.open(worktree .. "/.git", "w")
			if f then
				f:write("gitdir: ../../.bare/worktrees/feature-auth\n")
				f:close()
			end

			local result = wt.detect_source_worktree(project, worktree .. "/src")
			assert.are.equal(worktree, result)
		end)
	end)

	describe("not inside a worktree", function()
		it("returns nil when in bare repo directory", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local project = temp_dir .. "/proj5"
			local bare = project .. "/.bare"
			os.execute("mkdir -p " .. bare)

			local result = wt.detect_source_worktree(project, bare)
			assert.is_nil(result)
		end)
	end)
end)
