Lemon = {
  ws = {},
  ws_file = '.nvim.workspace.lua',
  term_buf = nil,
  term_win_cmd = 'belowright 12split',
}

function LoadWorkspace()
  -- Load persistent configuration from .workspace.lua
  local loaded, workspace = pcall(dofile, Lemon.ws_file)
  if not loaded then return nil end
  return workspace
end

function WriteWorkspace()
  -- A very minimal serializer for workspace configuration
  local s = { l = "", ls = {}, i = "" }
  local function w(v) s.l = s.l .. v end
  local function nl()
    s.ls[#s.ls + 1] = s.l; s.l = s.i;
  end
  local function wv(v)
    local t = type(v)
    if t == 'table' then
      w('{'); local pi = s.i; s.i = s.i .. "  "
      for k1, v1 in pairs(v) do
        nl(); w('['); wv(k1); w('] = '); wv(v1); w(',')
      end
      s.i = pi; nl(); w('}');
    elseif t == 'number' then
      w(tostring(v))
    elseif t == 'string' then
      w('"' .. v .. '"')
    else
      w(tostring(v))
    end
  end

  -- Write the workspace file
  w("return "); wv(Lemon.workspace); nl()
  vim.fn.writefile(s.ls, Lemon.ws_file)
end

-- Loads the workspace from the file, or return the default
---@param default table
---@return table
function InitWorkspace(default)
  Lemon.ws = LoadWorkspace()
  if Lemon.ws == nil then
    Lemon.ws = default
  end
  return Lemon.ws
end

function TermShow()
  local info = GetTermInfo()

  if info == nil then
    -- Create new terminal buffer
    vim.cmd(Lemon.term_win_cmd)
    vim.cmd('terminal')
    Lemon.term_buf = vim.api.nvim_get_current_buf()
    -- Mark buffer so we can identify it later
    vim.api.nvim_buf_set_var(Lemon.term_buf, 'lemon_terminal', true)
    info = GetTermInfo()
  elseif info.win == nil then
    -- Buffer exists but not visible, open it
    vim.cmd(Lemon.term_win_cmd)
    vim.api.nvim_win_set_buf(0, Lemon.term_buf)
  else
    -- Window is visible, switch to it
    vim.api.nvim_set_current_win(info.win)
  end
return info
end

-- Find or create persistent terminal buffer, open window, and run command
function TermRun(cmd)
  local info = TermShow()

  -- Send command to terminal
  vim.fn.chansend(info.job_id, '\021' .. cmd .. '\n')
  vim.fn.feedkeys("G", "n")
end

-- Get terminal buffer and job_id if valid, returns {buf, job_id, win}
-- win is nil if terminal is not currently visible
function GetTermInfo()
  if Lemon.term_buf == nil or not vim.api.nvim_buf_is_valid(Lemon.term_buf) then
    return nil
  end

  local job_id = vim.api.nvim_buf_get_var(Lemon.term_buf, 'terminal_job_id')

  -- Find window showing the terminal buffer
  local win = nil
  for _, w in ipairs(vim.api.nvim_list_wins()) do
    if vim.api.nvim_win_get_buf(w) == Lemon.term_buf then
      win = w
      break
    end
  end

  return { buf = Lemon.term_buf, job_id = job_id, win = win }
end

-- Compatibility wrapper - returns window ID if terminal is visible
function SwitchToExistingTerm()
  local info = GetTermInfo()
  return info and info.win or nil
end

-- Runs the make command and runs the callback when it completes
function MakeAnd(run_callback)
  -- Create a one-time autocmd that fires when make completes
  local group = vim.api.nvim_create_augroup('MakeAnd', { clear = false })

  vim.api.nvim_create_autocmd('QuickFixCmdPost', {
    group = group,
    pattern = 'make',
    once = true,
    callback = function()
      local qf_list = vim.fn.getqflist()
      local has_errors = false

      for _, item in ipairs(qf_list) do
        if item.valid == 1 then
          has_errors = true
          break
        end
      end

      vim.schedule(function()
        if not has_errors then
          run_callback()
        else
          vim.api.nvim_echo({ { "Build failed", "ErrorMsg" } }, false, {})
        end
      end)
    end
  })

  vim.cmd('silent make')
end

function TabCurrent()
  return vim.fn.tabpagenr()
end

function TabSwitch(tab)
  vim.cmd('tabnext ' .. tab)
end
