local assert = require("luassert")
local state = require("nvumi.state")
local stub = require("luassert.stub")

describe("nvumi.state", function()
  before_each(function()
    state.clear_state()
  end)

  it("should set and get a variable", function()
    state.set_variable("a", "42")
    assert.are.same("42", state.get_variable("a"))
  end)

  it("substitute_variables should replace variable names with their values", function()
    state.set_variable("var", "100")
    local result = state.substitute_variables("2*var+1")
    assert.are.same("2*(100)+1", result)
  end)

  it("clear_state should remove all state", function()
    state.set_variable("temp", "xyz")
    state.clear_state()
    assert.is_nil(state.get_variable("temp"))
  end)

  describe("state - output and yanking", function()
    local notify_stub, setreg_stub, getreg_stub, cursor_stub

    before_each(function()
      notify_stub = stub(vim, "notify")
      setreg_stub = stub(vim.fn, "setreg")
      getreg_stub = stub(vim.fn, "getreg").returns("")
      cursor_stub = stub(vim.api, "nvim_win_get_cursor").returns({ 1, 0 })
    end)

    after_each(function()
      notify_stub:revert()
      setreg_stub:revert()
      getreg_stub:revert()
      cursor_stub:revert()
    end)

    it("stores and retrieves last output", function()
      state.store_output(1, "last name lannister")
      assert.are.same("last name lannister", state.get_last_output())
      assert.are.same("last name lannister", state.outputs[1])
    end)

    it("yanks last output to clipboard", function()
      state.store_output(2, "call me kingslayer")
      state.yank_last_output()
      assert.stub(setreg_stub).was_called_with("+", "call me kingslayer")
      assert.stub(notify_stub).was_called_with("Yanked: call me kingslayer", vim.log.levels.INFO)
    end)

    it("notify error when nothing to yank", function()
      state.clear_state()
      state.yank_last_output()
      assert.stub(notify_stub).was_called_with("No output available to yank", vim.log.levels.ERROR)
    end)

    it("yanks all outputs to clipboard", function()
      state.store_output(1, "none this ill")
      state.store_output(2, "since kareem was a laker")
      state.yank_all_outputs()

      assert.stub(setreg_stub).was_called_with("+", "none this ill\nsince kareem was a laker")
      assert.stub(notify_stub).was_called_with("Yanked all evaluations", vim.log.levels.INFO)
    end)

    it("yanks output from a specific line", function()
      state.store_output(0, "im skating the equator")
      state.yank_output_on_line()
      assert.stub(setreg_stub).was_called_with("+", "im skating the equator")
      assert.stub(notify_stub).was_called_with("Yanked: im skating the equator", vim.log.levels.INFO)
    end)
  end)
end)
