vim.pack.add({
	{ src = "https://codeberg.org/mfussenegger/nvim-dap" },
})

local dap = require("dap")

-- GDB adapter for C/C++ (requires gdb 14.0+)
dap.adapters.gdb = {
	type = "executable",
	command = "gdb",
	args = { "--interpreter=dap", "--eval-command", "set print pretty on" },
}

-- Rust-specific adapter using rust-gdb for pretty-printing Rust types
dap.adapters["rust-gdb"] = {
	type = "executable",
	command = "rust-gdb",
	args = { "--interpreter=dap", "--eval-command", "set print pretty on" },
}

-- Delve adapter for Go (uses delve's built-in DAP mode)
dap.adapters.delve = function(callback, config)
	if config.mode == "remote" and config.request == "attach" then
		callback({
			type = "server",
			host = config.host or "127.0.0.1",
			port = config.port or "38697",
		})
	else
		callback({
			type = "server",
			port = "${port}",
			executable = {
				command = "dlv",
				args = { "dap", "-l", "127.0.0.1:${port}", "--log", "--log-output=dap" },
				detached = vim.fn.has("win32") == 0,
			},
		})
	end
end

-- C configurations
dap.configurations.c = {
	{
		name = "Launch",
		type = "gdb",
		request = "launch",
		program = function()
			return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/", "file")
		end,
		args = function()
			local input = vim.fn.input("Arguments: ")
			return vim.split(input, " ", { trimempty = true })
		end,
		cwd = "${workspaceFolder}",
		stopAtBeginningOfMainSubprogram = false,
	},
	{
		name = "Attach to process",
		type = "gdb",
		request = "attach",
		program = function()
			return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/", "file")
		end,
		pid = function()
			local name = vim.fn.input("Executable name (filter): ")
			return require("dap.utils").pick_process({ filter = name })
		end,
		cwd = "${workspaceFolder}",
	},
}

dap.configurations.cpp = dap.configurations.c

-- Rust configurations (using rust-gdb for pretty-printed types)
dap.configurations.rust = {
	{
		name = "Launch",
		type = "rust-gdb",
		request = "launch",
		program = function()
			return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/target/debug/", "file")
		end,
		args = function()
			local input = vim.fn.input("Arguments: ")
			return vim.split(input, " ", { trimempty = true })
		end,
		cwd = "${workspaceFolder}",
		stopAtBeginningOfMainSubprogram = false,
	},
	{
		name = "Attach to process",
		type = "rust-gdb",
		request = "attach",
		program = function()
			return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/target/debug/", "file")
		end,
		pid = function()
			local name = vim.fn.input("Executable name (filter): ")
			return require("dap.utils").pick_process({ filter = name })
		end,
		cwd = "${workspaceFolder}",
	},
}

-- Go configurations (using delve)
dap.configurations.go = {
	{
		type = "delve",
		name = "Debug",
		request = "launch",
		program = "${file}",
	},
	{
		type = "delve",
		name = "Debug test",
		request = "launch",
		mode = "test",
		program = "${file}",
	},
	{
		type = "delve",
		name = "Debug test (go.mod)",
		request = "launch",
		mode = "test",
		program = "./${relativeFileDirname}",
	},
}

-- Breakpoint signs
vim.fn.sign_define("DapBreakpoint", { text = "●", texthl = "DapBreakpoint", linehl = "", numhl = "" })
vim.fn.sign_define("DapBreakpointCondition", { text = "◆", texthl = "DapBreakpoint", linehl = "", numhl = "" })
vim.fn.sign_define("DapStopped", { text = "▶", texthl = "DapStopped", linehl = "DapStopped", numhl = "" })

-- Keybindings
vim.keymap.set("n", "<leader>gdb", dap.toggle_breakpoint, { desc = "Toggle breakpoint" })
vim.keymap.set("n", "<leader>gdB", function()
	dap.set_breakpoint(vim.fn.input("Breakpoint condition: "))
end, { desc = "Conditional breakpoint" })
vim.keymap.set("n", "<leader>gdc", dap.continue, { desc = "Continue / Launch" })
vim.keymap.set("n", "<leader>gds", dap.step_over, { desc = "Step over" })
vim.keymap.set("n", "<leader>gdi", dap.step_into, { desc = "Step into" })
vim.keymap.set("n", "<leader>gdo", dap.step_out, { desc = "Step out" })
vim.keymap.set("n", "<leader>gdr", dap.repl.open, { desc = "Open REPL" })
vim.keymap.set("n", "<leader>gdl", dap.run_last, { desc = "Run last" })
vim.keymap.set("n", "<leader>gdt", dap.terminate, { desc = "Terminate" })
vim.keymap.set("n", "<leader>gdh", function()
	require("dap.ui.widgets").hover()
end, { desc = "Hover variable" })
vim.keymap.set("v", "<leader>gdh", function()
	require("dap.ui.widgets").hover()
end, { desc = "Hover selection" })
vim.keymap.set("n", "<leader>gdF", function()
	require("dap.ui.widgets").centered_float(require("dap.ui.widgets").frames)
end, { desc = "Show frames" })
vim.keymap.set("n", "<leader>gdS", function()
	require("dap.ui.widgets").centered_float(require("dap.ui.widgets").scopes)
end, { desc = "Show scopes" })
