package aceboot::orm_demo

import aceboot::orm.*
import aceboot::orm.macros.*
import std.collection.*

/**
 * 实体:@Entity 生成 UserMapper + UserRepository。无需写 init()(仓颉对全字段有初值的类自动生成)。
 * @Id[] 主键(自增);@Column[] 数据列(列名=字段名),@Column["别名"] 自定义列名。
 */
@Entity["users"]
public class User {
    @Id[]
    public var id: Int64 = 0
    @Column[]
    public var name: String = ""
    @Column["age_years"] // 字段 age 映射到列 age_years(列别名)
    public var age: Int64 = 0
}

/** 演示外键:@ManyToOne["users"] 生成 FK 列 + DDL 的 FOREIGN KEY 约束。 */
@Entity["posts"]
public class Post {
    @Id[]
    public var id: Int64 = 0
    @Column[]
    public var title: String = ""
    @ManyToOne["users"] // 外键 -> users(id)
    public var authorId: Int64 = 0
}

func mkUser(name: String, age: Int64): User {
    let u = User()
    u.name = name
    u.age = age
    return u
}

/** 服务:@Transactional 把多步写操作包成一个原子事务。 */
class UserService {
    let repo: Repository<User>

    init(repo: Repository<User>) {
        this.repo = repo
    }

    @Transactional
    public func addTwo(a: User, b: User): Unit {
        repo.insert(a)
        repo.insert(b)
    }

    @Transactional
    public func addThenFail(a: User): Unit {
        repo.insert(a)
        throw OrmException("boom: rollback expected")
    }
}

main(): Int64 {
    let ds = DataSource(SqliteDriver(":memory:"))
    setGlobalDataSource(ds) // 供 @Transactional 与 @Entity 生成的 UserRepository() 使用
    let repo = UserRepository() // @Entity 生成的具体子类:无参构造,用全局数据源 + UserMapper
    repo.createTable()

    // ---- 基本 CRUD ----
    let alice = mkUser("alice", 30)
    let id = repo.insert(alice)
    println("insert alice -> id=${id}, 回填 alice.id=${alice.id}")
    repo.insert(mkUser("bob", 25))
    println("count=${repo.count()}")

    match (repo.findById(DbInt(id))) {
        case Some(u) => println("findById ${id} -> ${u.name}, age=${u.age}")
        case None => println("findById ${id} -> not found")
    }

    alice.age = 31
    repo.update(alice)
    println("update alice.age=31 -> 回查 age=${repo.findById(DbInt(id)).getOrThrow().age}")

    println("findBy name=bob -> ${repo.findBy("name", DbText("bob")).size} 行")

    // ---- 事务:提交 ----
    let svc = UserService(repo)
    svc.addTwo(mkUser("carol", 40), mkUser("dave", 50))
    println("addTwo 提交后 count=${repo.count()}")

    // ---- 事务:回滚 ----
    let before = repo.count()
    try {
        svc.addThenFail(mkUser("eve", 99))
    } catch (e: Exception) {
        println("addThenFail 抛出: ${e.message}")
    }
    println("回滚后 count=${repo.count()} (期望 ${before})")

    println("--- 全表 ---")
    for (u in repo.findAll()) {
        println("  #${u.id} ${u.name} (${u.age})")
    }

    // ---- 联表查询(QueryBuilder JOIN)----
    let postRepo = PostRepository()
    postRepo.createTable()
    // users 表里 alice=#1、bob=#2;插入两条帖子,外键 authorId 指向作者
    let pa = Post()
    pa.title = "alice writes ORM"
    pa.authorId = 1
    postRepo.insert(pa)
    let pb = Post()
    pb.title = "bob writes API"
    pb.authorId = 2
    postRepo.insert(pb)

    // 1) JOIN users 按作者名过滤,返回 Post 实体
    println("--- 联表:alice 写的帖子(JOIN users WHERE u.name='alice')---")
    let alicePosts = postRepo.createQueryBuilder("p").innerJoin("users", "u", "u.id = p.authorId").andWhere("u.name",
        "=", DbText("alice")).orderBy("p.id", "ASC").getMany()
    for (post in alicePosts) {
        println("  #${post.id} ${post.title} (authorId=${post.authorId})")
    }

    // 2) 联表投影:帖子标题 + 作者名(多表列,取原始 Row)
    println("--- 联表投影:标题 + 作者名 ---")
    for (r in postRepo.createQueryBuilder("p").innerJoin("users", "u", "u.id = p.authorId").orderBy("p.id",
        "ASC").getRawMany("p.title AS title, u.name AS author")) {
        println("  '${r.getText("title")}' by ${r.getText("author")}")
    }

    // ---- 由方言生成的 DDL(同一套实体,三种数据库语法)----
    println("--- 生成的 DDL(SQLite)---")
    println("users: ${SqliteDialect().createTable("users", UserMapper().columns())}")
    println("posts: ${SqliteDialect().createTable("posts", PostMapper().columns())}")

    ds.driver.close()
    return 0
}