local utils = require("ccc.utils.test")
local Keymap = require("ccc.kit.Vim.Keymap")
local t = Keymap.termcodes

vim.cmd("runtime plugin/ccc.lua")
local core = require("ccc").setup()

local function clear_buffer()
  utils.set_lines(0, -1, {})
  assert.same({ "" }, utils.get_lines(0, -1))
end

describe("Commands", function()
  before_each(function()
    clear_buffer()
  end)

  after_each(function()
    if utils.num_win() == 2 then
      vim.cmd("quit")
    end
    core.prev_colors:reset()
    core:reset_mode()
  end)

  it("g:ccc_color", function()
    Keymap.spec(function()
      vim.cmd("CccPick")
      assert.equal("#000000", vim.g.ccc_color)
      Keymap.send({ keys = t("<CR>"), remap = true }):await()
      assert.equal("", vim.g.ccc_color)
    end)
  end)

  describe("CccPick", function()
    it("Insert new color", function()
      Keymap.spec(function()
        vim.cmd("CccPick")
        assert.equal(2, utils.num_win(), "UI is not opened")
        Keymap.send({ keys = t("<CR>"), remap = true }):await()
        -- Initial color is #000000
        assert.equal("#000000", utils.get_line())
        assert.equal(1, utils.num_win(), "UI is not closed")
      end)
    end)

    it("Pick color", function()
      Keymap.spec(function()
        utils.set_lines(0, -1, { "#ffffff" })
        vim.cmd("CccPick")
        assert.equal("#ffffff", vim.g.ccc_color)
        Keymap.send({ keys = t("<CR>"), remap = true }):await()
      end)
    end)

    it("Replace color", function()
      Keymap.spec(function()
        utils.set_lines(0, -1, { "#ffffff" })
        vim.cmd("CccPick")
        -- Default mode; RGB (input), hex (output)
        -- Set all values to 0
        Keymap.send({ keys = t("0j0j0<CR>"), remap = true }):await()
        assert.equal("#000000", utils.get_line())
      end)
    end)

    describe("action", function()
      it("complete", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("<CR>"), remap = true }):await()
          -- Initial color is #000000
          assert.equal("#000000", utils.get_line())
        end)
      end)

      it("quit", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("q"), remap = true }):await()
          assert.equal("", utils.get_line())
        end)
      end)

      it("cycle input mode", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          -- Default mode; RGB (input), hex (output)
          -- Toggle to HSL
          Keymap.send({ keys = t("i"), remap = true }):await()
          -- Set to hsl(180 50% 50%)
          Keymap.send({ keys = t("MjMjM<CR>"), remap = true }):await()
          assert.equal("#40bfbf", utils.get_line())
        end)
      end)

      it("cycle output mode", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          -- Default mode; RGB (input), hex (output)
          -- Toggle to hex_short
          Keymap.send({ keys = t("o<CR>"), remap = true }):await()
          assert.equal("#000", utils.get_line())
        end)
      end)

      it("toggle_alpha", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          -- Default mode; RGB (input), hex (output)
          assert.equal(5, vim.fn.line("$"))
          Keymap.send({ keys = t("a"), remap = true }):await()
          assert.equal(6, vim.fn.line("$"))
          Keymap.send({ keys = t("<CR>"), remap = true }):await()
          assert.equal("#000000ff", utils.get_line())
        end)
      end)

      it("toggle prev colors", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("L<CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
          clear_buffer()
          vim.cmd("CccPick")
          -- Set default color
          assert.equal("#000000", vim.g.ccc_color)
          -- Select most recently used color
          Keymap.send({ keys = t("g<CR><CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
        end)
      end)

      it("goto next", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("L<CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("jL<CR>"), remap = true }):await()
          assert.equal("#ffff00", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("gw<CR><CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
        end)
      end)

      it("goto prev", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("L<CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("jL<CR>"), remap = true }):await()
          assert.equal("#ffff00", utils.get_line())
          clear_buffer()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("gwb<CR><CR>"), remap = true }):await()
          assert.equal("#ffff00", utils.get_line())
        end)
      end)

      it("goto tail", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("L<CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("jL<CR>"), remap = true }):await()
          assert.equal("#ffff00", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("jjL<CR>"), remap = true }):await()
          assert.equal("#ffffff", utils.get_line())
          clear_buffer()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("gW<CR><CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
        end)
      end)

      it("goto head", function()
        Keymap.spec(function()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("L<CR>"), remap = true }):await()
          assert.equal("#ff0000", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("jL<CR>"), remap = true }):await()
          assert.equal("#ffff00", utils.get_line())
          vim.cmd("CccPick")
          Keymap.send({ keys = t("jjL<CR>"), remap = true }):await()
          assert.equal("#ffffff", utils.get_line())
          clear_buffer()
          vim.cmd("CccPick")
          Keymap.send({ keys = t("gWB<CR><CR>"), remap = true }):await()
          assert.equal("#ffffff", utils.get_line())
        end)
      end)

      describe("increase", function()
        -- Default mapping: l / d / , (1 / 5 / 10)

        it("step by 1", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            assert.equal("#000000", vim.g.ccc_color)
            Keymap.send({ keys = t("l<CR>"), remap = true }):await()
            assert.equal("#010000", utils.get_line())
          end)
        end)

        it("step by 5", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            assert.equal("#000000", vim.g.ccc_color)
            Keymap.send({ keys = t("d<CR>"), remap = true }):await()
            assert.equal("#050000", utils.get_line())
          end)
        end)

        it("step by 10", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            assert.equal("#000000", vim.g.ccc_color)
            Keymap.send({ keys = t(",<CR>"), remap = true }):await()
            assert.equal("#0a0000", utils.get_line())
          end)
        end)
      end)

      describe("decrease", function()
        -- Default mapping: h / s / m (1 / 5 / 10)

        it("step by 1", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t("ll"), remap = true }):await()
            assert.equal("#020000", vim.g.ccc_color)
            Keymap.send({ keys = t("h<CR>"), remap = true }):await()
            assert.equal("#010000", utils.get_line())
          end)
        end)

        it("step by 5", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t("dd"), remap = true }):await()
            assert.equal("#0a0000", vim.g.ccc_color)
            Keymap.send({ keys = t("s<CR>"), remap = true }):await()
            assert.equal("#050000", utils.get_line())
          end)
        end)

        it("step by 10", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t(",,"), remap = true }):await()
            assert.equal("#140000", vim.g.ccc_color)
            Keymap.send({ keys = t("m<CR>"), remap = true }):await()
            assert.equal("#0a0000", utils.get_line())
          end)
        end)
      end)

      describe("set to", function()
        -- Default mapping: H / M / L (0 / 50 / 100), 1 - 9 (10% - 90%)

        it("0 %", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t("ll"), remap = true }):await()
            assert.equal("#020000", vim.g.ccc_color)
            Keymap.send({ keys = t("H<CR>"), remap = true }):await()
            assert.equal("#000000", utils.get_line())
          end)
        end)

        it("50 %", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t("M<CR>"), remap = true }):await()
            assert.equal("#800000", utils.get_line())
          end)
        end)

        it("100 %", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t("L<CR>"), remap = true }):await()
            assert.equal("#ff0000", utils.get_line())
          end)
        end)

        it("0 % - 90 % (mapped to numbers)", function()
          Keymap.spec(function()
            vim.cmd("CccPick")
            Keymap.send({ keys = t("0"), remap = true }):await()
            assert.equal("#000000", vim.g.ccc_color)
            Keymap.send({ keys = t("1"), remap = true }):await()
            assert.equal("#1a0000", vim.g.ccc_color)
            Keymap.send({ keys = t("2"), remap = true }):await()
            assert.equal("#330000", vim.g.ccc_color)
            Keymap.send({ keys = t("3"), remap = true }):await()
            assert.equal("#4d0000", vim.g.ccc_color)
            Keymap.send({ keys = t("4"), remap = true }):await()
            assert.equal("#660000", vim.g.ccc_color)
            Keymap.send({ keys = t("5"), remap = true }):await()
            assert.equal("#800000", vim.g.ccc_color)
            Keymap.send({ keys = t("6"), remap = true }):await()
            assert.equal("#990000", vim.g.ccc_color)
            Keymap.send({ keys = t("7"), remap = true }):await()
            assert.equal("#b30000", vim.g.ccc_color)
            Keymap.send({ keys = t("8"), remap = true }):await()
            assert.equal("#cc0000", vim.g.ccc_color)
            Keymap.send({ keys = t("9"), remap = true }):await()
            assert.equal("#e60000", vim.g.ccc_color)
          end)
        end)
      end)
    end)
  end)

  describe("<Plug>(ccc-insert)", function()
    it("the middle of a line", function()
      utils.set_lines(0, -1, { "foobar" })
      Keymap.spec(function()
        Keymap.send({
          "llli",
          { keys = t("<Plug>(ccc-insert)"), remap = true },
          { keys = t("MjMjM<CR>"), remap = true },
        }):await()
      end)
      assert.equal("foo#808080bar", utils.get_line())
    end)

    it("the beginning of a line", function()
      utils.set_lines(0, -1, { "foo" })
      Keymap.spec(function()
        Keymap.send({
          "I",
          { keys = t("<Plug>(ccc-insert)"), remap = true },
          { keys = t("MjMjM<CR>"), remap = true },
        }):await()
      end)
      assert.equal("#808080foo", utils.get_line())
    end)

    it("the end of a line", function()
      utils.set_lines(0, -1, { "foo" })
      Keymap.spec(function()
        Keymap.send({
          "A",
          { keys = t("<Plug>(ccc-insert)"), remap = true },
          { keys = t("MjMjM<CR>"), remap = true },
        }):await()
      end)
      assert.equal("foo#808080", utils.get_line())
    end)
  end)

  it("CccConvert", function()
    utils.set_lines(0, -1, { "#808080" })
    -- hex -> css_rgb -> css_hsl
    vim.cmd("CccConvert")
    assert.equal("rgb(128 128 128)", utils.get_line())
    vim.cmd("CccConvert")
    assert.equal("hsl(0 0% 50%)", utils.get_line())
    vim.cmd("CccConvert")
    assert.equal("#808080", utils.get_line())
  end)

  describe("<Plug>(ccc-select-color)", function()
    it("visual mode", function()
      utils.set_lines(0, -1, { "#00ff00" })
      Keymap.spec(function()
        Keymap.send({
          "llv",
          { keys = t("<Plug>(ccc-select-color)"), remap = true },
          "y",
        }):await()
      end)
      assert.equal("#00ff00", vim.fn.getreg())
    end)

    it("operator pending mode", function()
      utils.set_lines(0, -1, { "#ff00ff" })
      Keymap.spec(function()
        Keymap.send({
          "lly",
          { keys = t("<Plug>(ccc-select-color)"), remap = true },
        }):await()
      end)
      assert.equal("#ff00ff", vim.fn.getreg())
    end)
  end)
end)
