import ExpressionRunner from './ExpressionRunner'
import Program from "./core/Program";
import JSONObject from "./instances/JSONObject";
import LogicConsole from "./instances/LogicConsole";

console.debug("1.========testValidate========")
testValidate()
console.debug("2.========testAssert========")
testAssert()
console.debug("3.========testTry========")
testTry()
console.debug("4.========testPropertyType========")
testPropertyType()
console.debug("5.========testJSONArrayIndex========")
testJSONArrayIndex()
console.debug("6.========testArrayIndex========")
testArrayIndex()
console.debug("7.========testCompare========")
testCompare()
console.debug("8.========testJSONObject========")
testJSONObject()
console.debug("9.========testJSONArray========")
testJSONArray()
console.debug("10.========testFunctionCall========")
testFunctionCall()
console.debug("11.========testMath========")
testMath()
console.debug("12.========testString========")
testString()
console.debug("13.========testCondition========")
testCondition()
console.debug("14.========testThrow========")
testThrow()
console.debug("15.========testJSONArrayLoop========")
testJSONArrayLoop()
console.debug("16.========testJSONObjectLoop========")
testJSONObjectLoop()
console.debug("17.========testIntLoop========")
testIntLoop()
console.debug("18.========testContinueAndBreak========")
testContinueAndBreak()
console.debug("19.========testComment========")
testComment()
console.debug("20.========testReturn========")
testReturn()
console.debug("21.========testLambda========")
testLambda()

/**
 * validate
 */
function testValidate () {
  const expression = `
    validate {
        model: {
            required: true,
        },
        visible: {
            default: 1 + 1,
        },
        isAep: {
            default: 3
        },
        testJson: {
            required: true,
            items: {
                userid: {
                    required: true
                }
            }
        },
        testGroup: {
            mode: "atLeastOne",
            fields: [
                "test1",
                "test2"
            ]
        }
    },
    data.isAep == 3 :(
        log.info(123)
    ),null,
    log.info(data)
  `
  const data = {
    model: 'a',
    test1: 'b',
    isAep: null,
    testJson: {
      userid: {}
    }
  }
  runExpression(expression, data)
}

/**
 * assert
 */
function testAssert () {
  const expression = `
    c = 1,
    assert c == 1,
    log.debug("ok"),
    a = 1 + c,
    assert a == 2,
    log.debug("ok2")`
  runExpression(expression);
}

/**
 * try
 */
function testTry () {
  const expression = `
    a = 0,
    log.debug(a),
    try {
        assert c == 2
    } catch (WebException e) {
        log.debug(e),
        a = 1 + 1
    } catch (Exception e) {
        log.debug(e),
        a = 1 + 2
    },
    log.debug(a)
  `
  runExpression(expression)
}

/**
 * property
 */
function testPropertyType() {
  const expression = `
    a = 1,
    b = 2.0,
    c = {
        d: 1,
        e: {
            str: "123",
            你好: "中国"
        }
    },
    c.a = 1,
    log.debug(c.e.你好),
    log.debug(c["e"].str),
    e = c.d,
    f = "123",
    g = [],
    名称 = "123=>",
    log.debug(data.testArray[0]),
    return 名称
  `
  const data = {
    testArray: "zhang|b|c".split("\|")
  }
  runExpression(expression, data)
}

/**
 * JSONArray index
 */
function testJSONArrayIndex() {
  const expression = `
    a = [1,2,3,4,5],
    return a[4]
  `;
  runExpression(expression)
}

/**
 * array index
 */
function testArrayIndex() {
  const expression = `
    return data.a[4]
  `;
  const data = {
    a: [1,2,3,4,5]
  }
  runExpression(expression, data)
}

function testCompare() {
  const expression = `
    a = 0,
    a >= 0 :(
        a = a + 1,
        b = 1,
        a == b :(
            c = 3.0,
            a < c :(
                a + 2,
                a <= c :(
                    strA = $a$,
                    strB = $b$,
                    strC = $c$,
                    strA < strB && strA != strC :(
                        return $ok$
                    ),null
                ),null
            ),null
        ),null
    ),null
  `;
  runExpression(expression)
}

/**
 * JSONObject
 */
function testJSONObject() {
  const expression = `
    datas = {
        name: "张三",
        年龄: 15,
    },
    datas
  `
  runExpression(expression)
}

/**
 * JSONArray
 */
function testJSONArray() {
  const expression = `
    datas = ["a","b","c"],
    datas
  `
  runExpression(expression)
}

/**
 * function call
 */
function testFunctionCall() {
  const expression = `
    log.debug("test is ok")
  `
  runExpression(expression)
}

/**
 * math
 */
function testMath() {
  const expression = `
    a = 1,
    b = 2,
    c = a + b,
    c = c - 1,
    d = 5 * 8,
    e = d / 10,
    e = e % 2,
    c
  `
  runExpression(expression)
}

/**
 * string
 */
function testString() {
  const expression = `
    test1 = {}.toString(),
    log.debug(test1),
    a = $part1$,
    log.debug(a),
    b = "part2",
    log.debug(b),
    c = "{a}:{b}",
    log.debug(c),
    d = "{name}:张三",
    log.debug(d),
    e = "\\{name\\}:张三",
    log.debug(e),
    f = "\\"123\\"",
    log.debug(f),
    g = "\\$15.7",
    log.debug(g),
    h = $\\$15.7$,
    log.debug(h),
    i = "http:\\\\www.baidu.com",
    log.debug(i),
    j = $http://www.baidu.com$,
    log.debug(j)
  `
  runExpression(expression)
}

/**
 * condition
 */
function testCondition() {
  const expression = `
    1 != 1 :(
        throw "异常"
    ),null,
    1 + 1 != 2 :(
        throw "异常"
    ),null,
    !(2 > 3) && !(3 > 2):(
        throw "异常"
    ),null,
    2 > 3 :(
        throw "异常"
    ),null,
    !(3 > 2) :(
        throw "异常"
    ),null,
    y = 1 > 0,
    !y && 1 > 0 :(
        throw "异常"
    ),null
  `
  const data = {
    type: "1"
  }
  runExpression(expression, data)
}

/**
 * throw
 */
function testThrow() {
  const expression = `
    data.type == 2 :(
        throw "error",
        log.debug(result)
    ),null
  `
  const data = {
    type: "1"
  }
  runExpression(expression, data)
}

/**
 * JSONArray loop
 */
function testJSONArrayLoop() {
  const expression = `
    log.debug("test-JSONArray"),
    datas = [1,2,3,4,5],
    datas.each(
        log.debug(\${row}\$)
    ),
    log.debug("test-Set"),
    data.testSet.each(
        log.debug(\${row}\$)
    ),
    log.debug("test-Array"),
    data.testArray.each(
        log.debug(\${row}\$)
    )
  `
  const data = {
    testSet: [1, 2, 3, 4, 5],
    testArray: 'a|b|c'.split('\|')
  }
  runExpression(expression, data)
}

/**
 * JSONObject loop
 */
function testJSONObjectLoop() {
  const expression = `
    log.debug("test-JSONObject"),
    datas = {name: 1, age: 2},
    datas.each(
        log.debug(\${rowKey}：{row}$)
    ),
    log.debug("test-Map"),
    data.testMap.each(
        log.debug(\${rowKey}：{row}$)
    )
  `
  const data = {
    testMap: {
      name: "xxx",
      age: 18,
      gender: "男"
    }
  }
  runExpression(expression, data)
}

/**
 * int loop
 */
function testIntLoop() {
  const expression = `
    a = 5,
    a.each(
        log.debug(row)
    ),
    (0,5).each(
        log.debug(row)
    ),
    null
  `
  runExpression(expression)
}

/**
 * continue and break
 */
function testContinueAndBreak() {
  const expression = `
    datas = [1,2,3,4,5,6,7],
    datas.each(
        row == 3 :(
          continue
        ),row == 5:(
          break
        ),
        log.debug(row)
    )
  `
  runExpression(expression)
}

/**
 * comment
 */
function testComment () {
  const expression = `
    $//排序单表查询
    select {items}
    from {tablename}
    where {condition}
    order by {orderitem}
  `
  runExpression(expression)
}

/**
 * return
 */
function testReturn () {
  const expression = `
    data.type == 1 :(
        return "123",
        log.debug(123)
    ),(
        return 2
    ),
    log.debug(123)
  `
  const data = {
    type: 1
  }
  runExpression(expression, data)
}

/**
 * lambda
 */
function testLambda () {
  const expression = `
    log.debug("进入外层逻辑，参数：{data}"),
    age = 13,
    // 声明一个lambda块
    lambdaObj = (data) => {
        index = 1,
        log.debug("进入lambda了"),
        log.debug("传入lambda块的参数：{data}"),
        log.debug("外层的只读参数：{age}"),
        return "执行lambda完成"
    },
    log.debug("age参数:{age}"),
    result = lambdaObj.apply({
        name: "江超"
    }),
    result = lambdaObj.apply({
        name: "大神"
    }),
    log.debug("result:{result}"),
    return {
        func: lambdaObj
    }
  `
  const data = {
    type: 1
  }
  runExpression(expression, data)
}

function runExpression (expression: string, data?: any) {
  const program = new Program(expression)
  const d = program.parse()
  const params = {};
  if (data == null) {
    data = {}
  }
  params['data'] = data
  params['log'] = new LogicConsole()
  params['b'] = 5
  try {
    const result = d.invoke(new JSONObject(params))
    console.log(result)
    return result
  } catch (e) {
    throw e
  }
}
