require("plenary.async").tests.add_to_env()
local stickybuf = require("stickybuf")
local test_util = require("tests.test_util")

a.describe("stickybuf", function()
  after_each(function()
    test_util.reset_editor()
  end)

  a.it("can pin a buffer", function()
    vim.cmd.edit({ args = { "README.md" } })
    local winid = vim.api.nvim_get_current_win()
    local readme_bufnr = vim.api.nvim_get_current_buf()
    vim.cmd.PinBuffer()
    local license_bufnr = vim.fn.bufadd("LICENSE")
    vim.cmd.edit({ args = { "LICENSE" } })
    a.util.sleep(10)
    assert.equals(license_bufnr, vim.api.nvim_get_current_buf())
    assert.not_equals(winid, vim.api.nvim_get_current_win())
    assert.equals(2, #vim.api.nvim_tabpage_list_wins(0))
    assert.equals(readme_bufnr, vim.api.nvim_win_get_buf(winid))
  end)

  a.it("can unpin a buffer", function()
    vim.cmd.edit({ args = { "README.md" } })
    local winid = vim.api.nvim_get_current_win()
    local readme_bufnr = vim.api.nvim_get_current_buf()
    vim.cmd.PinBuffer()
    vim.cmd.Unpin()
    local license_bufnr = vim.fn.bufadd("LICENSE")
    vim.cmd.edit({ args = { "LICENSE" } })
    a.util.sleep(10)
    assert.equals(license_bufnr, vim.api.nvim_get_current_buf())
    assert.equals(winid, vim.api.nvim_get_current_win())
    assert.equals(1, #vim.api.nvim_tabpage_list_wins(0))
  end)

  a.it("can pin a buffer when bufhidden=wipe", function()
    vim.cmd.edit({ args = { "README.md" } })
    vim.bo.bufhidden = "wipe"
    local winid = vim.api.nvim_get_current_win()
    local readme_bufnr = vim.api.nvim_get_current_buf()
    vim.cmd.PinBuffer()
    local license_bufnr = vim.fn.bufadd("LICENSE")
    vim.cmd.edit({ args = { "LICENSE" } })
    a.util.sleep(10)
    assert.equals(license_bufnr, vim.api.nvim_get_current_buf())
    assert.not_equals(winid, vim.api.nvim_get_current_win())
    assert.equals(2, #vim.api.nvim_tabpage_list_wins(0))
    assert.equals(readme_bufnr, vim.api.nvim_win_get_buf(winid))
  end)

  a.it("can pin a buffer when bufhidden=", function()
    vim.cmd.edit({ args = { "README.md" } })
    vim.bo.bufhidden = ""
    local winid = vim.api.nvim_get_current_win()
    local readme_bufnr = vim.api.nvim_get_current_buf()
    vim.cmd.PinBuffer()
    local license_bufnr = vim.fn.bufadd("LICENSE")
    vim.cmd.edit({ args = { "LICENSE" } })
    a.util.sleep(10)
    assert.equals(license_bufnr, vim.api.nvim_get_current_buf())
    assert.not_equals(winid, vim.api.nvim_get_current_win())
    assert.equals(2, #vim.api.nvim_tabpage_list_wins(0))
    assert.equals(readme_bufnr, vim.api.nvim_win_get_buf(winid))
  end)

  a.describe("pin buftype", function()
    a.it("allows buffers with same type", function()
      vim.cmd.edit({ args = { "foo" } })
      vim.bo.buftype = "nofile"
      local winid = vim.api.nvim_get_current_win()
      vim.cmd.PinBuftype()
      local bar_bufnr = vim.fn.bufadd("bar")
      vim.bo[bar_bufnr].buftype = "nofile"
      vim.cmd.edit({ args = { "bar" } })
      a.util.sleep(10)
      assert.equals(bar_bufnr, vim.api.nvim_get_current_buf())
      assert.equals(winid, vim.api.nvim_get_current_win())
      assert.equals(1, #vim.api.nvim_tabpage_list_wins(0))
    end)

    a.it("rejects buffers with different type", function()
      vim.cmd.edit({ args = { "foo" } })
      vim.bo.buftype = "nofile"
      local winid = vim.api.nvim_get_current_win()
      local foo_bufnr = vim.api.nvim_get_current_buf()
      vim.cmd.PinBuftype()
      local license_bufnr = vim.fn.bufadd("LICENSE")
      vim.cmd.edit({ args = { "LICENSE" } })
      vim.wait(1000, function()
        return vim.api.nvim_get_current_win() ~= winid
      end, 10)
      assert.equals(license_bufnr, vim.api.nvim_get_current_buf())
      assert.not_equals(winid, vim.api.nvim_get_current_win())
      assert.equals(2, #vim.api.nvim_tabpage_list_wins(0))
      assert.equals(foo_bufnr, vim.api.nvim_win_get_buf(winid))
    end)
  end)

  a.describe("pin filetype", function()
    a.it("allows buffers with same filetype", function()
      vim.cmd.edit({ args = { "foo" } })
      vim.bo.filetype = "txt"
      local winid = vim.api.nvim_get_current_win()
      vim.api.nvim_get_current_buf()
      vim.cmd.PinFiletype()
      local bar_bufnr = vim.fn.bufadd("bar")
      vim.bo[bar_bufnr].filetype = "txt"
      vim.cmd.edit({ args = { "bar" } })
      a.util.sleep(10)
      assert.equals(bar_bufnr, vim.api.nvim_get_current_buf())
      assert.equals(winid, vim.api.nvim_get_current_win())
      assert.equals(1, #vim.api.nvim_tabpage_list_wins(0))
    end)

    a.it("rejects buffers with different filetype", function()
      vim.cmd.edit({ args = { "foo" } })
      vim.bo.filetype = "txt"
      local winid = vim.api.nvim_get_current_win()
      local foo_bufnr = vim.api.nvim_get_current_buf()
      vim.cmd.PinFiletype()
      local readme_bufnr = vim.fn.bufadd("README.md")
      vim.cmd.edit({ args = { "README.md" } })
      vim.wait(1000, function()
        return vim.api.nvim_get_current_win() ~= winid
      end, 10)
      assert.equals(readme_bufnr, vim.api.nvim_get_current_buf())
      assert.not_equals(winid, vim.api.nvim_get_current_win())
      assert.equals(2, #vim.api.nvim_tabpage_list_wins(0))
      assert.equals(foo_bufnr, vim.api.nvim_win_get_buf(winid))
    end)
  end)

  a.it("Calls the restore_callback after restoring a buffer", function()
    vim.cmd.edit({ args = { "README.md" } })
    local winid = vim.api.nvim_get_current_win()
    local readme_bufnr = vim.api.nvim_get_current_buf()
    local restore_called_in_win
    stickybuf.pin(0, {
      restore_callback = function(restore_win)
        restore_called_in_win = restore_win
      end,
    })
    local license_bufnr = vim.fn.bufadd("LICENSE")
    vim.cmd.edit({ args = { "LICENSE" } })
    a.util.sleep(10)
    assert.equals(winid, restore_called_in_win)
  end)
end)
