/*
 * test_query.cj - 查询构建器测试
 */

package tybb2026::tycj_orm

import std.collection.*
import std.unittest.*

@TestClass
class TestQueryBuilder {

    @TestCase
    func testSelectBuilderBasic(): Unit {
        let builder = SelectBuilder("users")
        builder.column("id").column("name")
        let sql = builder.build()

        @Assert(sql.contains("SELECT"))
        @Assert(sql.contains("FROM users"))
    }

    @TestCase
    func testSelectBuilderWithWhere(): Unit {
        let builder = SelectBuilder("users")
        builder.where_("age > 18")
        let sql = builder.build()

        @Assert(sql.contains("WHERE"))
        @Assert(sql.contains("age > 18"))
    }

    @TestCase
    func testSelectBuilderWithLimit(): Unit {
        let builder = SelectBuilder("users")
        builder.limit(10)
        let sql = builder.build()

        @Assert(sql.contains("LIMIT"))
        @Assert(sql.contains("10"))
    }

    @TestCase
    func testSelectBuilderWithOffset(): Unit {
        let builder = SelectBuilder("users")
        builder.offset(20)
        let sql = builder.build()

        @Assert(sql.contains("OFFSET"))
        @Assert(sql.contains("20"))
    }

    @TestCase
    func testSelectBuilderWithLimitAndOffset(): Unit {
        let builder = SelectBuilder("users")
        builder.limit(10).offset(20)
        let sql = builder.build()

        @Assert(sql.contains("LIMIT"))
        @Assert(sql.contains("OFFSET"))
    }

    @TestCase
    func testInsertBuilder(): Unit {
        let builder = InsertBuilder("users")
        builder.value("name", "John").value("age", "25")
        let sql = builder.build()

        @Assert(sql.contains("INSERT INTO"))
        @Assert(sql.contains("users"))
        @Assert(sql.contains("VALUES"))
    }

    @TestCase
    func testUpdateBuilder(): Unit {
        let builder = UpdateBuilder("users")
        builder.set("name", "John").where_("id = 1")
        let sql = builder.build()

        @Assert(sql.contains("UPDATE"))
        @Assert(sql.contains("SET"))
        @Assert(sql.contains("WHERE"))
    }

    @TestCase
    func testDeleteBuilder(): Unit {
        let builder = DeleteBuilder("users")
        builder.where_("id = 1")
        let sql = builder.build()

        @Assert(sql.contains("DELETE FROM"))
        @Assert(sql.contains("WHERE"))
    }

    @TestCase
    func testConditionBuilderEq(): Unit {
        let cb = ConditionBuilder()
        cb.eq("name", "John")
        let condition = cb.build()

        @Assert(condition.contains("name = ?"))
    }

    @TestCase
    func testConditionBuilderLike(): Unit {
        let cb = ConditionBuilder()
        cb.like("name", "John")
        let params = cb.getParameters()

        @Assert(params.size == 1)
        // 验证通配符被正确转义
        @Assert(params[0].contains("%"))
    }

    @TestCase
    func testConditionBuilderIn(): Unit {
        let cb = ConditionBuilder()
        let values = ArrayList<String>()
        values.add("1")
        values.add("2")
        values.add("3")
        cb.isIn("id", values)
        let condition = cb.build()

        @Assert(condition.contains("IN"))
        @Assert(condition.contains("?"))
    }

    @TestCase
    func testConditionBuilderInEmptyList(): Unit {
        let cb = ConditionBuilder()
        let values = ArrayList<String>()
        cb.isIn("id", values)
        let condition = cb.build()

        @Assert(condition == "1=0")
    }

    @TestCase
    func testJoinClause(): Unit {
        let join = JoinClause(JoinType.Inner, "orders", "o", "users.id = o.user_id")
        let sql = join.toSql()

        @Assert(sql.contains("INNER JOIN"))
        @Assert(sql.contains("orders"))
        @Assert(sql.contains("ON"))
    }

    @TestCase
    func testSelectBuilderWithJoin(): Unit {
        let builder = SelectBuilder("users")
        builder.innerJoin("orders", "o", "users.id = o.user_id")
        let sql = builder.build()

        @Assert(sql.contains("JOIN"))
        @Assert(sql.contains("orders"))
    }

    @TestCase
    func testSelectBuilderWithOrderBy(): Unit {
        let builder = SelectBuilder("users")
        builder.orderBy("name", Direction.Asc)
        let sql = builder.build()

        @Assert(sql.contains("ORDER BY"))
        @Assert(sql.contains("ASC"))
    }

    @TestCase
    func testSelectBuilderDistinct(): Unit {
        let builder = SelectBuilder("users")
        builder.distinct()
        let sql = builder.build()

        @Assert(sql.contains("DISTINCT"))
    }
}

@TestClass
class TestSqlBuilder {

    @TestCase
    func testSelectFrom(): Unit {
        let selectBuilder = SqlBuilder.selectFrom("users")
        let sql = selectBuilder.build()
        @Assert(sql.contains("SELECT"))
        @Assert(sql.contains("FROM users"))
    }

    @TestCase
    func testInsert(): Unit {
        let insertBuilder = SqlBuilder.insert("users")
        insertBuilder.value("name", "John")
        let sql = insertBuilder.build()
        @Assert(sql.contains("INSERT INTO"))
    }

    @TestCase
    func testUpdate(): Unit {
        let updateBuilder = SqlBuilder.update("users")
        updateBuilder.set("name", "John")
        let sql = updateBuilder.build()
        @Assert(sql.contains("UPDATE"))
    }

    @TestCase
    func testDeleteFrom(): Unit {
        let deleteBuilder = SqlBuilder.deleteFrom("users")
        deleteBuilder.where_("id = 1")
        let sql = deleteBuilder.build()
        @Assert(sql.contains("DELETE FROM"))
    }

    @TestCase
    func testConditions(): Unit {
        let cb = SqlBuilder.conditions()
        cb.eq("name", "John")
        let condition = cb.build()
        @Assert(condition.contains("name = ?"))
    }
}

@TestClass
class TestUtils {

    @TestCase
    func testJoinStrings(): Unit {
        let list = ArrayList<String>()
        list.add("a")
        list.add("b")
        list.add("c")
        let result = joinStrings(list, ", ")

        @Assert(result == "a, b, c")
    }

    @TestCase
    func testJoinStringsEmpty(): Unit {
        let list = ArrayList<String>()
        let result = joinStrings(list, ", ")

        @Assert(result == "")
    }

    @TestCase
    func testToUpperCaseString(): Unit {
        let result = toUpperCaseString("hello")
        @Assert(result == "HELLO")
    }

    @TestCase
    func testToLowerCaseString(): Unit {
        let result = toLowerCaseString("HELLO")
        @Assert(result == "hello")
    }

    @TestCase
    func testContainsIgnoreCase(): Unit {
        @Assert(containsIgnoreCase("Hello World", "hello"))
        @Assert(containsIgnoreCase("Hello World", "WORLD"))
        @Assert(!containsIgnoreCase("Hello World", "foo"))
    }

    @TestCase
    func testIsValidIdentifier(): Unit {
        @Assert(isValidIdentifier("users"))
        @Assert(isValidIdentifier("user_name"))
        @Assert(isValidIdentifier("_users"))
        @Assert(isValidIdentifier("users123"))
        @Assert(!isValidIdentifier("123users"))
        @Assert(!isValidIdentifier(""))
        @Assert(!isValidIdentifier("user-name"))
    }

    @TestCase
    func testEscapeIdentifier(): Unit {
        let result = escapeIdentifier("user-name;DROP TABLE users--")
        @Assert(!result.contains("-"))
        @Assert(!result.contains(";"))
        @Assert(!result.contains(" "))
    }
}