local M = {}

-- State management
local state = {
  initialized = false,
  lookup_conceal = nil,
}

-- Helper function to get the plugin root directory
local function get_plugin_root()
  local source = debug.getinfo(2, "S").source
  local file = string.sub(source, 2) -- Remove the '@' prefix
  local dir = string.match(file, "(.*/)")

  -- Navigate up two directories: from lua/utils/ to the plugin root
  return string.gsub(dir, "lua/utils/$", "")
end

-- Try to load a dynamic library
local function try_load(path)
  local success, result = pcall(function()
    return package.loadlib(path, "luaopen_lookup_conceal")
  end)

  if success and type(result) == "function" then
    return result
  end

  return nil
end

-- Initialize the library
function M.initialize()
  if state.initialized then
    return state.lookup_conceal ~= nil
  end

  local plugin_root = get_plugin_root()

  -- Try with different extensions based on the platform
  local lib_paths = {
    plugin_root .. "/build/lookup_conceallua51.dylib",
    plugin_root .. "/build/lookup_conceallua51.so",
    plugin_root .. "/build/lookup_conceallua51.dll",
    plugin_root .. "/build/lookup_concealluajit.dylib",
    plugin_root .. "/build/lookup_concealluajit.so",
    plugin_root .. "/build/lookup_concealluajit.dll",
  }

  local lib_func = nil
  for _, path in ipairs(lib_paths) do
    lib_func = try_load(path)
    if lib_func then
      break
    end
  end

  if not lib_func then
    vim.notify(
      "Failed to load lookup_conceal library. Make sure you run 'make lua51' or 'make luajit' first.",
      vim.log.levels.ERROR
    )
    state.initialized = true
    return false
  end

  state.lookup_conceal = lib_func()
  state.initialized = true
  return true
end

-- Ensure the library is loaded before usage
function M.ensure_loaded()
  if not state.initialized then
    return M.initialize()
  end
  return state.lookup_conceal ~= nil
end

--- Function to convert LaTeX math symbols to Unicode
--- @param text string: The LaTeX math symbol to convert
--- @param pattern '"escape"'|'"conceal"'|'"font"'|'"sub"'|'"sup"' Valid values from PatternType enum
--- @param type? string: Type of concealment (e.g., "cal", "frak", "bold", etc.)
--- @return string: The converted Unicode symbol or the original text if not found
function M.lookup_math_symbol(text, pattern, type)
  return state.lookup_conceal.lookup_math_symbol({ text = text, pattern = pattern or "conceal", mode = type or "" })
    or text
end

--- Batch lookup function for better performance
--- @param batch table: Array of {text, pattern, mode} tables
--- @return table: Array of results
function M.lookup_batch(batch)
  if not state.lookup_conceal then
    return batch -- Return original if not loaded
  end

  return state.lookup_conceal.lookup_batch(batch) or batch
end

--- Lookup all math symbols with any patterns and any types
--- Warning: This can be slow for large input
--- @param text string: The LaTeX math symbol to convert
--- @return string: The converted Unicode symbol or the original text if not found
function M.lookup_all(text)
  if not state.lookup_conceal then
    return text
  end

  local pattern, type
  if text:sub(1, 1) == "\\" then
    local brace_start = text:find("{", 2, true)
    local brace_end = text:find("}", brace_start, true)
    if brace_start and brace_end and brace_start > 2 then
      local cmd = text:sub(1, brace_start - 1)
      local arg = text:sub(brace_start + 1, brace_end - 1)
      pattern = "font"
      type = cmd
      text = arg
    else
      pattern = "conceal"
      type = ""
    end
  end
  ---SAFETY: If pattern or type is nil, return the original text
  if pattern == nil or type == nil then
    return text
  end
  return state.lookup_conceal.lookup_math_symbol({ text = text, pattern = pattern, mode = type }) or text
end

return M
