local logger = require("continue.logger.logger")
local fs = require("continue.utils.fs")
local M = {}

M.file = ""

---@type table<string, Continue.Extension>
local handlers = {}

local function load_extension(ext)
  if type(ext) == "string" then
    return require(ext)
  elseif type(ext) == "function" then
    return ext()
  else
    logger.error("Invalid extension format")
  end
end

---@param handler Continue.Extension
function M.register(handler)
  handlers[handler.id] = {
    load = handler.load,
    save = handler.save,
    id = handler.id,
    enabled = handler.enabled,
  }
end

---@param opts Continue.Config
function M.init(opts)
  for _, extension in ipairs(opts.extensions) do
    if extension then
      pcall(function()
        local loaded_extension = load_extension(extension)
        M.register(loaded_extension)
      end)
    end
  end
end

---@param session_opts SessionOpts
function M.save(session_opts)
  for handler_name, handler in pairs(handlers) do
    if not handler.enabled or handler.enabled(session_opts) then
      local success, handler_data = pcall(function()
        return handler.save(session_opts)
      end)
      if not success then
        logger.error("Error while saving session extensions data: %s", handler_data)
      end
      if success then
        local can_be_json, encoding_result = pcall(function()
          vim.json.encode(handler_data)
        end)

        if not can_be_json then
          logger.error(
            "Data encoded by extensions handler %s cannot be saved: %s",
            handler.id,
            encoding_result
          )
        else
          local ok, res = pcall(function()
            fs.write_json_file(
              fs.join_paths(
                session_opts.project_data_path,
                string.format("extension_%s.json", handler_name)
              ),
              handler_data
            )
          end)

          if not ok then
            logger.error("Failed to load data for extension %s, error: %s", handler_name, res)
          end
        end
      end
    end
  end
end

---@param session_opts SessionOpts
function M.load(session_opts)
  for handler_name, handler in pairs(handlers) do
    if not handler.enabled or handler.enabled(session_opts) then
      local success, data = pcall(function()
        return fs.read_json_file(
          fs.join_paths(
            session_opts.project_data_path,
            string.format("extension_%s.json", handler_name)
          )
        )
      end)

      if not success then
        if data == "file_error" then
          logger.debug("Session data for extension %s doesn't exist", handler_name)
        else
          logger.error(
            "Session data generated by extension %s is corrupted. Cannot load it",
            handler_name
          )
        end
      end

      if success then
        if not data or type(data) ~= "table" then
          logger.error("Saved data for extension %s has an incorrect format or value", handler_name)
        else
          local ok, res = pcall(function()
            handler.load(data, session_opts)
          end)

          if not ok then
            logger.error("Failed to load data for extension %s, error: %s", handler_name, res)
          end
        end
      end
    end
  end
end

return M
