/*
 * test_repository.cj - 仓库模块测试
 */

package tybb2026::tycj_orm

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

@TestClass
class TestInt64Repository {

    @TestCase
    func testSave(): Unit {
        let repo = Int64Repository<TestEntity>(
            getIdFunc: (entity) => entity.id,
            setIdFunc: (entity, id) => { entity.id = id }
        )

        let entity = TestEntity(id: 0, name: "张三")
        let saved = repo.save(entity)

        @Assert(saved.id > 0)
        @Assert(saved.name == "张三")
    }

    @TestCase
    func testFindById(): Unit {
        let repo = Int64Repository<TestEntity>(
            getIdFunc: (entity) => entity.id,
            setIdFunc: (entity, id) => { entity.id = id }
        )

        // 先保存
        let entity = TestEntity(id: 0, name: "李四")
        let saved = repo.save(entity)

        // 再查找
        match (repo.findById(saved.id)) {
            case Some(found) =>
                @Assert(found.name == "李四")
            case None =>
                @Assert(false)
        }
    }

    @TestCase
    func testFindAll(): Unit {
        let repo = Int64Repository<TestEntity>(
            getIdFunc: (entity) => entity.id,
            setIdFunc: (entity, id) => { entity.id = id }
        )

        // 保存多个实体
        repo.save(TestEntity(id: 0, name: "张三"))
        repo.save(TestEntity(id: 0, name: "李四"))
        repo.save(TestEntity(id: 0, name: "王五"))

        let all = repo.findAll()
        @Assert(all.size == 3)
    }

    @TestCase
    func testCount(): Unit {
        let repo = Int64Repository<TestEntity>(
            getIdFunc: (entity) => entity.id,
            setIdFunc: (entity, id) => { entity.id = id }
        )

        repo.save(TestEntity(id: 0, name: "张三"))
        repo.save(TestEntity(id: 0, name: "李四"))

        @Assert(repo.count() == 2)
    }

    @TestCase
    func testDeleteById(): Unit {
        let repo = Int64Repository<TestEntity>(
            getIdFunc: (entity) => entity.id,
            setIdFunc: (entity, id) => { entity.id = id }
        )

        let saved = repo.save(TestEntity(id: 0, name: "张三"))
        @Assert(repo.count() == 1)

        repo.deleteById(saved.id)
        @Assert(repo.count() == 0)
    }

    @TestCase
    func testExistsById(): Unit {
        let repo = Int64Repository<TestEntity>(
            getIdFunc: (entity) => entity.id,
            setIdFunc: (entity, id) => { entity.id = id }
        )

        let saved = repo.save(TestEntity(id: 0, name: "张三"))
        @Assert(repo.existsById(saved.id))
        @Assert(!repo.existsById(999))
    }
}

@TestClass
class TestStringRepository {

    @TestCase
    func testSave(): Unit {
        let repo = StringRepository<TestEntity2>(
            getIdFunc: (entity) => entity.code
        )

        let entity = TestEntity2(code: "001", name: "项目A")
        let saved = repo.save(entity)

        @Assert(saved.code == "001")
        @Assert(saved.name == "项目A")
    }

    @TestCase
    func testFindById(): Unit {
        let repo = StringRepository<TestEntity2>(
            getIdFunc: (entity) => entity.code
        )

        repo.save(TestEntity2(code: "001", name: "项目A"))

        match (repo.findById("001")) {
            case Some(found) =>
                @Assert(found.name == "项目A")
            case None =>
                @Assert(false)
        }
    }
}

@TestClass
class TestPageRequest {

    @TestCase
    func testOf(): Unit {
        let pageable = PageRequest.of(page: 0, size: 10)

        @Assert(pageable.getPageNumber() == 0)
        @Assert(pageable.getPageSize() == 10)
        @Assert(pageable.getOffset() == 0)
    }

    @TestCase
    func testOffset(): Unit {
        let pageable = PageRequest.of(page: 2, size: 20)

        @Assert(pageable.getOffset() == 40)
    }

    @TestCase
    func testNavigation(): Unit {
        let pageable = PageRequest.of(page: 1, size: 10)

        @Assert(pageable.hasPrevious())
        @Assert(pageable.previous().getPageNumber() == 0)
        @Assert(pageable.next().getPageNumber() == 2)
        @Assert(pageable.first().getPageNumber() == 0)
    }
}

@TestClass
class TestSort {

    @TestCase
    func testAscending(): Unit {
        let sort = Sort.ascending("name")

        @Assert(!sort.isEmpty())
        let orders = sort.getOrders()
        @Assert(orders.size == 1)
        @Assert(orders[0].isAscending())
        @Assert(orders[0].property == "name")
    }

    @TestCase
    func testDescending(): Unit {
        let sort = Sort.descending("created_at")

        let orders = sort.getOrders()
        @Assert(orders[0].isDescending())
    }

    @TestCase
    func testCombined(): Unit {
        let sort = Sort.ascending("name").andDescending("created_at")

        let orders = sort.getOrders()
        @Assert(orders.size == 2)
        @Assert(orders[0].isAscending())
        @Assert(orders[1].isDescending())
    }

    @TestCase
    func testToSql(): Unit {
        let sort = Sort.ascending("name").andDescending("created_at")
        let sql = sort.toSql()

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

@TestClass
class TestPage {

    @TestCase
    func testPageBasic(): Unit {
        let content = ArrayList<TestEntity>()
        content.add(TestEntity(id: 1, name: "张三"))
        content.add(TestEntity(id: 2, name: "李四"))

        let pageable = PageRequest.of(page: 0, size: 10)
        let page = Page<TestEntity>(content: content, totalElements: 25, pageable: pageable)

        @Assert(page.getContent().size == 2)
        @Assert(page.getTotalElements() == 25)
        @Assert(page.getTotalPages() == 3)
        @Assert(page.getNumber() == 0)
        @Assert(page.getSize() == 10)
        @Assert(page.isFirst())
        @Assert(!page.isLast())
        @Assert(page.hasNext())
        @Assert(!page.hasPrevious())
    }

    @TestCase
    func testPageNavigation(): Unit {
        let content = ArrayList<TestEntity>()
        let pageable = PageRequest.of(page: 1, size: 10)
        let page = Page<TestEntity>(content: content, totalElements: 30, pageable: pageable)

        @Assert(!page.isFirst())
        @Assert(!page.isLast())
        @Assert(page.hasNext())
        @Assert(page.hasPrevious())
    }
}

// 测试实体类(使用 Int64 ID)
class TestEntity {
    public var id: Int64
    public var name: String

    public init(id!: Int64 = 0, name!: String = "") {
        this.id = id
        this.name = name
    }
}

// 测试实体类(使用 String ID)
class TestEntity2 {
    public let code: String
    public var name: String

    public init(code!: String = "", name!: String = "") {
        this.code = code
        this.name = name
    }
}