import XCTest
@testable import Rosetta

@MainActor
final class MigrationHarnessTests: XCTestCase {
    private var ctx: DBTestContext!

    override func setUpWithError() throws {
        ctx = DBTestContext()
    }

    override func tearDownWithError() throws {
        ctx.teardown()
        ctx = nil
    }

    func testLegacySyncOnlyMigrationReconcilesWithoutSQLiteUpsertSyntaxFailure() async throws {
        try await ctx.bootstrap()

        DatabaseManager.shared.close()
        let sqlite = try ctx.openSQLite()
        let rerunMigrations = DatabaseManager.migrationIdentifiers.dropFirst(3)
        let deleteList = rerunMigrations.map { "'\($0)'" }.joined(separator: ",")
        try sqlite.execute("DELETE FROM grdb_migrations WHERE identifier IN (\(deleteList))")
        try sqlite.execute("DROP TABLE IF EXISTS accounts_sync_times")
        try sqlite.execute("DELETE FROM sync_cursors")
        try sqlite.execute("INSERT INTO sync_cursors(account, timestamp) VALUES ('\(ctx.account)', 1234567890123)")

        try DatabaseManager.shared.bootstrap(accountPublicKey: ctx.account)
        let cursor = DatabaseManager.shared.loadSyncCursor(account: ctx.account)
        XCTAssertEqual(cursor, 1_234_567_890_123)
    }

    func testPartialReconcileBackfillsNullIds() async throws {
        try await ctx.bootstrap()
        DatabaseManager.shared.saveSyncCursor(account: ctx.account, timestamp: 9_001)

        DatabaseManager.shared.close()
        let sqlite = try ctx.openSQLite()
        try sqlite.execute("UPDATE accounts_sync_times SET id = NULL WHERE account = '\(ctx.account)'")
        try sqlite.execute("DELETE FROM grdb_migrations WHERE identifier = '\(DatabaseManager.migrationV7SyncCursorReconcile)'")

        try DatabaseManager.shared.bootstrap(accountPublicKey: ctx.account)

        let check = try ctx.openSQLite()
        let rows = try check.query(
            "SELECT id, last_sync FROM accounts_sync_times WHERE account = ? LIMIT 1",
            [.text(ctx.account)]
        )
        XCTAssertEqual(rows.count, 1)
        XCTAssertNotEqual(rows.first?["id"], "")
        XCTAssertNotEqual(rows.first?["id"], "0")
        XCTAssertEqual(rows.first?["last_sync"], "9001")
    }

    func testMonotonicSyncCursorNeverDecreases() async throws {
        try await ctx.bootstrap()

        DatabaseManager.shared.saveSyncCursor(account: ctx.account, timestamp: 1_700_000_005_000)
        DatabaseManager.shared.saveSyncCursor(account: ctx.account, timestamp: 1_700_000_004_999)
        DatabaseManager.shared.saveSyncCursor(account: ctx.account, timestamp: 1_700_000_006_500)

        XCTAssertEqual(DatabaseManager.shared.loadSyncCursor(account: ctx.account), 1_700_000_006_500)
    }

    func testCompatibilityMirrorWritesAccountsSyncTimesAndSyncCursors() async throws {
        try await ctx.bootstrap()
        DatabaseManager.shared.saveSyncCursor(account: ctx.account, timestamp: 77_777)

        let sqlite = try ctx.openSQLite()
        let accountsRows = try sqlite.query(
            "SELECT last_sync, id FROM accounts_sync_times WHERE account = ? LIMIT 1",
            [.text(ctx.account)]
        )
        let legacyRows = try sqlite.query(
            "SELECT timestamp FROM sync_cursors WHERE account = ? LIMIT 1",
            [.text(ctx.account)]
        )

        XCTAssertEqual(accountsRows.first?["last_sync"], "77777")
        XCTAssertNotEqual(accountsRows.first?["id"], "")
        XCTAssertNotEqual(accountsRows.first?["id"], "0")
        XCTAssertEqual(legacyRows.first?["timestamp"], "77777")
    }
}
