package aceboot::orm.postgres

import aceboot::orm.common.*

import std.unittest.*
import std.unittest.testmacro.*
import aceboot::orm.macros.*

// @VersionColumn 乐观锁跨库验证(真连 PostgreSQL 容器;无 PG 环境则跳过,保证无库环境仍绿)。
// 关键修复点:PG 驱动经 PQcmdTuples 暴露受影响行数,使 0 行更新触发 OrmException。

@Entity["optlock_pg_accounts"]
public class OptLockPgAccount {
    @Id[]
    public var id: Int64 = 0
    @Column[]
    public var balance: Int64 = 0
    @VersionColumn[]
    public var version: Int64 = 0
}

// 连接 PG;连不上(无环境)返回 None 让调用方跳过。
func openPgForOptLock(): ?PostgresDriver {
    try {
        return Some(PostgresDriver(PG_CONNINFO))
    } catch (e: Exception) {
        println("[optlock-pg] skip: ${e.message}")
        return None
    }
}

@Test
func test_pg_version_column_optimistic_lock() {
    let driver = match (openPgForOptLock()) {
        case Some(d) => d
        case None => return
    }
    let ds = DataSource(driver)
    setGlobalDataSource(ds)
    let repo = OptLockPgAccountRepository()
    driver.exec("DROP TABLE IF EXISTS optlock_pg_accounts", [])
    repo.createTable()

    let a = OptLockPgAccount()
    a.balance = 100
    let id = repo.insert(a)
    @Expect(repo.findById(DbInt(id)).getOrThrow().version, 1) // insert 置版本 1

    // 两份并发副本,均持版本 1。
    let copyA = repo.findById(DbInt(id)).getOrThrow()
    let copyB = repo.findById(DbInt(id)).getOrThrow()

    copyA.balance = 200
    repo.update(copyA) // 成功:命中 1 行,DB 版本 -> 2
    @Expect(driver.affectedRows(), 1) // PG 受影响行数已真实暴露
    @Expect(repo.findById(DbInt(id)).getOrThrow().version, 2)
    @Expect(repo.findById(DbInt(id)).getOrThrow().balance, 200)

    // copyB 仍持旧版本 1:WHERE version=1 命中 0 行 -> 应抛 OrmException。
    copyB.balance = 999
    var threw = false
    try {
        repo.update(copyB)
    } catch (_: OrmException) {
        threw = true
    }
    @Expect(threw, true)
    // 冲突未改数据:余额仍是 copyA 写入的 200。
    @Expect(repo.findById(DbInt(id)).getOrThrow().balance, 200)

    driver.exec("DROP TABLE IF EXISTS optlock_pg_accounts", [])
    driver.close()
    println("[optlock-pg] PostgreSQL @VersionColumn optimistic lock passed against real server")
}

@Test
func test_pg_affected_rows_reports_zero_and_count() {
    let driver = match (openPgForOptLock()) {
        case Some(d) => d
        case None => return
    }
    driver.exec("DROP TABLE IF EXISTS optlock_pg_affected", [])
    driver.exec("CREATE TABLE optlock_pg_affected (id INTEGER PRIMARY KEY, n INTEGER)", [])
    let ins = driver.exec("INSERT INTO optlock_pg_affected (id, n) VALUES (1, 10)", [])
    @Expect(ins, 1) // exec 直接返回受影响行数(对标 JDBC executeUpdate)
    @Expect(driver.affectedRows(), 1) // 插入 1 行

    // 命中 0 行的 UPDATE:受影响行数应为 0(乐观锁冲突判定的基础)。
    let miss = driver.exec("UPDATE optlock_pg_affected SET n = 20 WHERE id = 999", [])
    @Expect(miss, 0)
    @Expect(driver.affectedRows(), 0)

    // 命中 1 行的 UPDATE:受影响行数为 1。
    let hit = driver.exec("UPDATE optlock_pg_affected SET n = 30 WHERE id = 1", [])
    @Expect(hit, 1)
    @Expect(driver.affectedRows(), 1)

    // PG 无 last-insert-id 概念:恒 0(自增 id 走 INSERT ... RETURNING)。
    @Expect(driver.lastInsertId(), 0)

    driver.exec("DROP TABLE IF EXISTS optlock_pg_affected", [])
    driver.close()
}