local config = require("nvim-aws").config
local log = require("nvim-aws.utilities.log")

local M = {}

local default_env = {
	["AWS_PROFILE"] = config.aws.aws_profile,
	["AWS_DEFAULT_OUTPUT"] = "json",
	["AWS_PAGER"] = "",
	["PATH"] = os.getenv("PATH") or "",
}

--- Execute an AWS CLI command with input and process the results
--- Return an empty table if input is nil
--- @param command_path table the aws command path
--- @param input nil|table the input table
--- @param callbacks nil|{stdout?: fun(err: string, data: string), stderr?: fun(err: string, data: string), on_exit?: fun(out: vim.SystemCompleted)}
--- @return {success: boolean, data?: table, error?: string }|{success: boolean, job: vim.SystemObj}
function M.execute_aws_command(command_path, input, callbacks)
	if not input then
		return { success = true, data = {} }
	else
		return M.execute_aws_job(vim.list_extend(command_path, input), callbacks)
	end
end

--- Execute an AWS CLI command with an input generated from --generate-cli-skeleton and process the results
--- Return a table that was generated by --generate-cli-skeleton
--- @param command_path table the aws command path
--- @param input nil|table the input table
--- @param callbacks nil|{stdout?: fun(err: string, data: string), stderr?: fun(err: string, data: string), on_exit?: fun(out: vim.SystemCompleted)}
--- @return {success: boolean, data?: table, error?: string }|{success: boolean, job: vim.SystemObj}
function M.execute_aws_command_skeleton(command_path, input, callbacks)
	if not input then
		return M.execute_aws_job(vim.list_extend(command_path, { "--generate-cli-skeleton" }), callbacks)
	else
		if next(input) == nil then
			return M.execute_aws_job(vim.list_extend(command_path, { "--cli-input-json", "{}" }), callbacks)
		else
			local json_input = vim.fn.json_encode(input)
			return M.execute_aws_job(vim.list_extend(command_path, { "--cli-input-json", json_input }), callbacks)
		end
	end
end

--- Execute an AWS CLI command and process the results
--- @param args table The arguments for the AWS CLI command
--- @param callbacks nil|{stdout?: fun(err: string, data: string), stderr?: fun(err: string, data: string), on_exit?: fun(out: vim.SystemCompleted)}
--- @return {success: boolean, data?: table, error?: string }|{success: boolean, job: vim.SystemObj}
function M.execute_aws_job(args, callbacks)
	local concatenated_args = table.concat(args, " ")

	local opts = {
		env = default_env,
		text = true,
	}

	if callbacks then
		log.info("starting job: aws " .. concatenated_args .. "...")

		opts.stdout = callbacks.stdout or false
		opts.stderr = callbacks.stderr or false

		local system_obj = vim.system({ "aws", unpack(args) }, opts, function(out)
			log.info("finished job: aws " .. concatenated_args .. " with code " .. out.code)
			if callbacks.on_exit then
				callbacks.on_exit(out)
			end
		end)

		return { success = true, job = system_obj }
	else
		local systemCompleteResult = vim.system({ "aws", unpack(args) }, opts):wait()

		if systemCompleteResult.code == 0 then
			log.info("successful job: aws " .. concatenated_args)
			local result = systemCompleteResult.stdout or ""

			if result == "" then
				log.debug("successful job: empty response: aws " .. concatenated_args)
				return { success = true, data = {}, error = nil }
			end

			local parsed_data = vim.json.decode(result, { luanil = { object = true, array = true } })
			return { success = true, data = parsed_data, error = nil }
		else
			local err = systemCompleteResult.stderr or "Unknown error"
			log.error("failed job: aws " .. concatenated_args .. ": " .. err)
			return { success = false, data = nil, error = err }
		end
	end
end

return M
