-- 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")

describe("hook permission system", 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("load_hook_permissions", function()
		it("returns empty table when file does not exist", function()
			local perms = wt.load_hook_permissions(temp_dir .. "/nonexistent")
			assert.are.same({}, perms)
		end)

		it("loads valid permissions file", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local perm_dir = temp_dir .. "/perms1/.local/share/wt"
			os.execute("mkdir -p " .. perm_dir)

			local f = io.open(perm_dir .. "/hook-dirs.lua", "w")
			if f then
				f:write('{\n\t["/home/user/project1"] = true,\n\t["/home/user/project2"] = false,\n}\n')
				f:close()

				local perms = wt.load_hook_permissions(temp_dir .. "/perms1")
				assert.are.equal(true, perms["/home/user/project1"])
				assert.are.equal(false, perms["/home/user/project2"])
			else
				pending("could not write test file")
			end
		end)

		it("returns empty table for malformed file", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local perm_dir = temp_dir .. "/perms2/.local/share/wt"
			os.execute("mkdir -p " .. perm_dir)

			local f = io.open(perm_dir .. "/hook-dirs.lua", "w")
			if f then
				f:write('this is not valid lua {{{}')
				f:close()

				local perms = wt.load_hook_permissions(temp_dir .. "/perms2")
				assert.are.same({}, perms)
			else
				pending("could not write test file")
			end
		end)
	end)

	describe("save_hook_permissions", function()
		it("creates directory if it does not exist", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local home = temp_dir .. "/save1"
			wt.save_hook_permissions({ ["/test/project"] = true }, home)

			local f = io.open(home .. "/.local/share/wt/hook-dirs.lua", "r")
			assert.is_not_nil(f)
			if f then
				f:close()
			end
		end)

		it("saves permissions correctly", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local home = temp_dir .. "/save2"
			wt.save_hook_permissions({
				["/project/a"] = true,
				["/project/b"] = false,
			}, home)

			local perms = wt.load_hook_permissions(home)
			assert.are.equal(true, perms["/project/a"])
			assert.are.equal(false, perms["/project/b"])
		end)

		it("overwrites existing permissions", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local home = temp_dir .. "/save3"
			wt.save_hook_permissions({ ["/old"] = true }, home)
			wt.save_hook_permissions({ ["/new"] = false }, home)

			local perms = wt.load_hook_permissions(home)
			assert.is_nil(perms["/old"])
			assert.are.equal(false, perms["/new"])
		end)
	end)
end)

describe("run_hooks", 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("copy hooks", function()
		it("copies files from source to target", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local source = temp_dir .. "/source1"
			local target = temp_dir .. "/target1"
			local home = temp_dir .. "/home1"
			os.execute("mkdir -p " .. source)
			os.execute("mkdir -p " .. target)

			local f = io.open(source .. "/config.json", "w")
			if f then
				f:write('{"key": "value"}\n')
				f:close()
			end

			wt.save_hook_permissions({ ["/project"] = true }, home)

			local hooks = { copy = { "config.json" } }
			wt.run_hooks(source, target, hooks, "/project", home)

			local copied = io.open(target .. "/config.json", "r")
			assert.is_not_nil(copied)
			if copied then
				local content = copied:read("*a")
				copied:close()
				assert.is_truthy(content:match("key"))
			end
		end)

		it("creates parent directories for nested paths", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local source = temp_dir .. "/source2"
			local target = temp_dir .. "/target2"
			local home = temp_dir .. "/home2"
			os.execute("mkdir -p " .. source .. "/nested/path")
			os.execute("mkdir -p " .. target)

			local f = io.open(source .. "/nested/path/file.txt", "w")
			if f then
				f:write("nested content\n")
				f:close()
			end

			wt.save_hook_permissions({ ["/project2"] = true }, home)

			local hooks = { copy = { "nested/path/file.txt" } }
			wt.run_hooks(source, target, hooks, "/project2", home)

			local copied = io.open(target .. "/nested/path/file.txt", "r")
			assert.is_not_nil(copied)
			if copied then
				copied:close()
			end
		end)
	end)

	describe("symlink hooks", function()
		it("creates symlinks from target to source", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local source = temp_dir .. "/source3"
			local target = temp_dir .. "/target3"
			local home = temp_dir .. "/home3"
			os.execute("mkdir -p " .. source .. "/node_modules")
			os.execute("mkdir -p " .. target)

			local f = io.open(source .. "/node_modules/package.json", "w")
			if f then
				f:write('{"name": "test"}\n')
				f:close()
			end

			wt.save_hook_permissions({ ["/project3"] = true }, home)

			local hooks = { symlink = { "node_modules" } }
			wt.run_hooks(source, target, hooks, "/project3", home)

			local link_check, _ = wt.run_cmd("test -L " .. target .. "/node_modules && echo yes")
			assert.is_truthy(link_check:match("yes"))
		end)
	end)

	describe("run hooks", function()
		it("executes commands in target directory", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local source = temp_dir .. "/source4"
			local target = temp_dir .. "/target4"
			local home = temp_dir .. "/home4"
			os.execute("mkdir -p " .. source)
			os.execute("mkdir -p " .. target)

			wt.save_hook_permissions({ ["/project4"] = true }, home)

			local hooks = { run = { "touch ran-hook.txt" } }
			wt.run_hooks(source, target, hooks, "/project4", home)

			local ran = io.open(target .. "/ran-hook.txt", "r")
			assert.is_not_nil(ran)
			if ran then
				ran:close()
			end
		end)
	end)

	describe("permission denied", function()
		it("skips hooks when permission is false", function()
			if not temp_dir then
				pending("temp_dir not available")
				return
			end
			local source = temp_dir .. "/source5"
			local target = temp_dir .. "/target5"
			local home = temp_dir .. "/home5"
			os.execute("mkdir -p " .. source)
			os.execute("mkdir -p " .. target)

			local f = io.open(source .. "/shouldnt-copy.txt", "w")
			if f then
				f:write("content\n")
				f:close()
			end

			wt.save_hook_permissions({ ["/project5"] = false }, home)

			local hooks = { copy = { "shouldnt-copy.txt" } }
			wt.run_hooks(source, target, hooks, "/project5", home)

			local not_copied = io.open(target .. "/shouldnt-copy.txt", "r")
			assert.is_nil(not_copied)
		end)
	end)
end)
