local M = require "modal"
M()
local maxi = require("modal").maxi(M)
local mini = require("modal").mini(M)
local describe = require("busted").describe
local it = require("busted").it
local assert = require("busted").assert

assert.pat = function(a, b)
   assert.same(a(0, 1), b(0, 1))
end

describe("symb", function()
   it("should parse steps to lua String or Id", function()
      local hello
      assert.same("hello", maxi "hello")
      assert.same(hello, maxi "'hello")
   end)
   it("should parse steps to lua String or Id", function()
      assert.same(42, maxi "42")
   end)
end)

describe("set", function()
   it("should parse set to lua var set in only top level????", function()
      assert.same(1, maxi "a = 1; 'a")
   end)
   -- it("should parse set a func call to var", function()
   --    assert.same("a = fast(pure2(2), pure2(1)); ", to_str " a = $ fast 2 1 ")
   -- end)
   -- it("should parse set a sexp to var", function()
   --    assert.same("a = fast(2, 1); ", to_str " a = (fast 2 1) ")
   -- end)
   -- it("should parse set a mini-notation to var", function()
   --    assert.same([[a = fastcat({pure("bd"),pure("sd")}); ]], to_str "a = [bd sd]")
   -- end)
end)

describe("step", function()
   it("numbers", function()
      assert.same(-1, maxi "-1")
   end)
end)

describe("slice", function()
   it("should parse mini slice as a first class", function()
      assert.same("bd", maxi "bd")
   end)
end)

describe("subcycle", function()
   it("should parse mini subcycle as a first class", function()
      assert.pat(fastcat { "bd" }, mini "[bd]")
      assert.pat(fastcat { "bd", "sd" }, mini "[bd sd]")
   end)
end)

describe("stack", function()
   it("should parse mini stack as a first class", function()
      assert.pat(stack { pure "bd", pure "sd" }, mini "[bd, sd]")
      assert.pat(stack { fastcat { "bd", "bd" }, fastcat { "sd", "sd" } }, mini "[bd bd, sd sd]")
   end)
end)

describe("slow_seq", function()
   it("should parse mini slow_seq as a first class", function()
      assert.pat(slowcat { "bd" }, mini "<bd>")
      -- assert.pat(slowcat { "bd", "sd" }, mini "<bd sd>")
      -- assert.pat(slowcat { 0, 1, 2, 3, 4 }, mini "<0 .. 4>")
   end)
end)

describe("polymeter", function()
   it("should parse mini polymeter as a first class", function()
      assert.pat(fastcat { "bd", "sd", "hh" }, mini "{bd sd hh}")
      assert.pat(fastcat { "bd", "sd", "hh" }, mini "{bd sd hh}%3")
      assert.pat(fastcat { "bd", "sd" }, mini "{bd sd hh}%2")
      assert.pat(stack { fastcat { "bd", "sd" }, fastcat { 1, 2 } }, mini "{bd sd hh, 1 2 3 4}%2")
   end)
end)

describe("choose", function()
   it("should parse mini choose as first class", function()
      assert.pat(randcat { pure "bd", pure "sd", pure "cp" }, mini "[bd | sd | cp]")
      assert.pat(randcat { fastcat { "bd", "sd" }, pure "sd", pure "cp" }, mini "[bd sd | sd | cp]")
      assert.pat(randcat { fastcat { "bd", "sd" }, pure "sd", pure "cp" }, mini "< bd sd | sd | cp >")
   end)
end)

describe("dotStack", function()
   it("should parse mini dotStack as first class", function()
      assert.pat(fastcat { fastcat { 1, 2 }, fastcat { 3, 4 } }, mini "[1 2 . 3 4]")
   end)
   it("should parse mini dotStack as first class", function()
      assert.pat(slowcat { fastcat { 1, 2 }, fastcat { 3, 4 } }, mini "<1 2 . 3 4>")
   end)
end)

describe("ops", function()
   it("should parse mini ops as a first class", function()
      assert.pat(fast(2, "bd"), mini "bd*2")
      assert.pat(euclidRot(3, 8, 0, "bd"), mini "bd(3,8)")
      assert.pat(degradeBy(0.5, "bd"), mini "bd?")
      assert.pat(fastcat { "bd", "bd", "sd" }, mini "[bd! sd]")
      assert.pat(pure { 0.3, 0.5, 2 }, mini "0.3:0.5:2")
   end)
   it("weight", function()
      assert.pat(timecat { 2, "bd", 1, "sd" }, mini "[bd@2 sd]")
      assert.pat(timecat { 3, "bd", 2, "sd" }, mini "[bd __ sd _]")
      assert.pat(arrange { 2, "bd", 1, "sd" }, mini "<bd@2 sd>")
   end)
end)

describe("tidal ops", function()
   it("should parse tidal ops as a first class", function()
      assert.pat(note(3), maxi [[note 2 +| note 1]])
      assert.pat(pure { s = "bd", room = 0.2 }, maxi [[s bd |> room 0.2]])
      assert.pat(pure { s = "bd", room = 0.2 }, maxi [[s bd >|| room 0.2]])
   end)
end)

describe("list(p)", function()
   it("should parse sexp as a first class", function()
      assert.same(3, maxi "(+ 1 2)")
      assert.same(-1, maxi "(- 1 2)")
   end)
   it("should parse sexp func call as a first class", function()
      assert.pat(fast(1, 2), maxi "(fast 1 2)")
      assert.pat(fast(1, pure(2)), maxi "(fast 1 (pure 2))")
   end)
   it("should parse nested function calls", function()
      assert.same(fast(2, 1)(1, 2), maxi "((fast 2 1) 1 2)")
   end)
   it("should do prefix operator", function()
      assert.same(2, maxi "(+ 1 1)")
   end)
   it("should do currying for arithmetic", function()
      assert.same(2, maxi "((+ 1) 1)")
      assert.same(2, maxi "((+) 1 1)")
   end)
   -- TODO: curry for all functions
end)
