from __future__ import annotations

import unittest
from unittest.mock import MagicMock, patch

from govoplan_core.db.migration_lock import (
    deployment_migration_lock,
    migration_lock_key,
)


class MigrationLockTests(unittest.TestCase):
    def test_lock_key_is_stable_and_namespaced(self) -> None:
        first = migration_lock_key("installation-a", "release")
        self.assertEqual(first, migration_lock_key("installation-a", "release"))
        self.assertNotEqual(first, migration_lock_key("installation-b", "release"))
        self.assertNotEqual(first, migration_lock_key("installation-a", "dev"))
        self.assertGreaterEqual(first, -(2**63))
        self.assertLess(first, 2**63)

    def test_non_postgres_migration_lock_is_a_noop(self) -> None:
        entered = False
        with deployment_migration_lock(
            "sqlite+pysqlite:///:memory:",
            installation_id="installation-a",
            migration_track="release",
        ):
            entered = True
        self.assertTrue(entered)

    def test_postgres_lock_is_held_for_the_guarded_operation(self) -> None:
        result = MagicMock()
        result.scalar_one.return_value = True
        connection = MagicMock()
        connection.execute.return_value = result
        engine = MagicMock()
        engine.connect.return_value = connection
        with patch(
            "govoplan_core.db.migration_lock.create_engine",
            return_value=engine,
        ):
            with deployment_migration_lock(
                "postgresql://user:secret@db.example.test/govoplan",
                installation_id="installation-a",
                migration_track="release",
            ):
                self.assertEqual(1, connection.execute.call_count)

        self.assertEqual(2, connection.execute.call_count)
        connection.close.assert_called_once_with()
        engine.dispose.assert_called_once_with()


if __name__ == "__main__":
    unittest.main()
