"""
NanaSQLite Async Performance Benchmarks

pytest-benchmarkを使用した非同期操作のパフォーマンス計測
"""

import asyncio
import contextlib
import importlib.util
import os
import tempfile

import pytest

# pytest-benchmarkがインストールされているか確認
pytest_benchmark_available = importlib.util.find_spec("pytest_benchmark") is not None


# ==================== Fixtures ====================


@pytest.fixture
def db_path():
    with tempfile.TemporaryDirectory() as tmpdir:
        yield os.path.join(tmpdir, "async_bench.db")


@pytest.fixture
def async_db_instance(db_path):
    """AsyncNanaSQLiteインスタンスをベンチマーク全体で共有（接続オーバーヘッドを排除）"""
    from nanasqlite import AsyncNanaSQLite

    db = AsyncNanaSQLite(db_path)
    yield db
    # 完全にクリーンアップ（_benchmark_loopを使用して確実にclose()を実行する）
    with contextlib.suppress(Exception):
        run_async(db.close())


@pytest.fixture
def async_db_with_data_instance(db_path):
    """1000件のデータが入ったAsync DBインスタンス"""
    from nanasqlite import AsyncNanaSQLite

    async def setup():
        db = AsyncNanaSQLite(db_path)
        data = {f"key_{i}": {"index": i, "data": "x" * 100} for i in range(1000)}
        await db.batch_update(data)
        return db

    db = run_async(setup())
    yield db
    with contextlib.suppress(Exception):
        run_async(db.close())


# ベンチマーク用の永続的イベントループ
_benchmark_loop = asyncio.new_event_loop()


def run_async(coro):
    """非同期関数を同期的に実行するヘルパー（ループを再利用）"""
    return _benchmark_loop.run_until_complete(coro)


# ==================== Async Write Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncWriteBenchmarks:
    """非同期書き込みパフォーマンスのベンチマーク"""

    def test_async_single_write(self, benchmark, async_db_instance):
        """非同期単一書き込み"""
        counter = [0]

        def write_single():
            async def _write():
                await async_db_instance.aset(f"key_{counter[0]}", {"data": "value", "number": counter[0]})
                counter[0] += 1

            run_async(_write())

        benchmark(write_single)

    def test_async_nested_write(self, benchmark, async_db_instance):
        """ネストしたデータの非同期書き込み"""
        counter = [0]
        nested_data = {"level1": {"level2": {"level3": {"data": [1, 2, 3, {"nested": True}]}}}}

        def write_nested():
            async def _write():
                await async_db_instance.aset(f"nested_{counter[0]}", nested_data)
                counter[0] += 1

            run_async(_write())

        benchmark(write_nested)

    def test_async_batch_write_100(self, benchmark, async_db_instance):
        """非同期バッチ書き込み（100件）"""
        counter = [0]

        def batch_write():
            async def _batch():
                data = {f"batch_{counter[0]}_{i}": {"index": i} for i in range(100)}
                await async_db_instance.abatch_update(data)
                counter[0] += 1

            run_async(_batch())

        benchmark(batch_write)

    def test_async_batch_write_1000(self, benchmark, async_db_instance):
        """非同期バッチ書き込み（1000件）"""
        counter = [0]

        def batch_write():
            async def _batch():
                data = {f"batch_{counter[0]}_{i}": {"index": i} for i in range(1000)}
                await async_db_instance.abatch_update(data)
                counter[0] += 1

            run_async(_batch())

        benchmark(batch_write)


# ==================== Async Read Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncReadBenchmarks:
    """非同期読み込みパフォーマンスのベンチマーク"""

    def test_async_single_read(self, benchmark, async_db_with_data_instance):
        """非同期単一読み込み"""

        def read_single():
            async def _read():
                return await async_db_with_data_instance.aget("key_500")

            return run_async(_read())

        benchmark(read_single)

    def test_async_batch_get(self, benchmark, async_db_with_data_instance):
        """非同期バッチ取得（100件）"""
        keys = [f"key_{i}" for i in range(100)]

        def batch_get():
            async def _get():
                return await async_db_with_data_instance.abatch_get(keys)

            return run_async(_get())

        benchmark(batch_get)

    def test_async_bulk_load_1000(self, benchmark, db_path):
        """非同期一括ロード（1000件）"""
        from nanasqlite import AsyncNanaSQLite

        # データ準備（ここだけは新規接続でロード性能を測る必要があるため async with を使用）
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.batch_update({f"key_{i}": {"index": i} for i in range(1000)})

        run_async(setup())

        def bulk_load():
            async def _load():
                async with AsyncNanaSQLite(db_path, bulk_load=True):
                    pass

            run_async(_load())

        benchmark(bulk_load)

    def test_async_get_fresh(self, benchmark, async_db_with_data_instance):
        """非同期get_fresh（キャッシュバイパス）"""

        def get_fresh():
            async def _get():
                return await async_db_with_data_instance.get_fresh("key_500")

            return run_async(_get())

        benchmark(get_fresh)


# ==================== Async Dict Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncDictOperationsBenchmarks:
    """非同期dict操作のベンチマーク"""

    def test_async_keys_1000(self, benchmark, async_db_with_data_instance):
        """非同期keys()取得（1000件）"""

        def get_keys():
            async def _keys():
                return await async_db_with_data_instance.akeys()

            return run_async(_keys())

        benchmark(get_keys)

    def test_async_values_1000(self, benchmark, async_db_with_data_instance):
        """非同期values()取得（1000件）"""

        def get_values():
            async def _values():
                return await async_db_with_data_instance.avalues()

            return run_async(_values())

        benchmark(get_values)

    def test_async_contains_check(self, benchmark, async_db_with_data_instance):
        """非同期存在確認"""

        def check_contains():
            async def _check():
                return await async_db_with_data_instance.acontains("key_500")

            return run_async(_check())

        benchmark(check_contains)

    def test_async_len(self, benchmark, async_db_with_data_instance):
        """非同期len()取得"""

        def get_len():
            async def _len():
                return await async_db_with_data_instance.alen()

            return run_async(_len())

        benchmark(get_len)

    def test_async_to_dict_1000(self, benchmark, async_db_with_data_instance):
        """非同期to_dict()変換（1000件）"""

        def get_to_dict():
            async def _to_dict():
                return await async_db_with_data_instance.ato_dict()

            return run_async(_to_dict())

        benchmark(get_to_dict)

    def test_async_pop(self, benchmark, async_db_instance):
        """非同期pop()操作"""
        counter = [0]

        def pop_op():
            async def _pop():
                await async_db_instance.aset(f"pop_key_{counter[0]}", {"value": counter[0]})
                result = await async_db_instance.apop(f"pop_key_{counter[0]}")
                counter[0] += 1
                return result

            return run_async(_pop())

        benchmark(pop_op)

    def test_async_setdefault(self, benchmark, async_db_instance):
        """非同期setdefault()操作"""
        counter = [0]

        def setdefault_op():
            async def _setdefault():
                result = await async_db_instance.asetdefault(f"default_key_{counter[0]}", {"default": True})
                counter[0] += 1
                return result

            return run_async(_setdefault())

        benchmark(setdefault_op)

    def test_async_batch_get_100(self, benchmark, async_db_with_data_instance):
        """非同期バッチ取得（100件）"""
        keys = [f"key_{i}" for i in range(100)]

        def batch_get_op():
            async def _get():
                return await async_db_with_data_instance.abatch_get(keys)

            return run_async(_get())

        benchmark(batch_get_op)

    def test_async_batch_delete_100(self, benchmark, async_db_instance):
        """非同期バッチ削除（100件）"""
        counter = [0]

        def batch_del_op():
            async def _del_prepare():
                keys = [f"delbatch_{counter[0]}_{i}" for i in range(100)]
                await async_db_instance.abatch_update({k: {"v": 1} for k in keys})
                await async_db_instance.abatch_delete(keys)
                counter[0] += 1

            run_async(_del_prepare())

        benchmark(batch_del_op)


# ==================== Async Concurrency Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncConcurrencyBenchmarks:
    """非同期並行処理のベンチマーク"""

    def test_async_concurrent_reads_10(self, benchmark, db_path):
        """並行読み込み（10件同時）"""
        from nanasqlite import AsyncNanaSQLite

        # データ準備
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.batch_update({f"key_{i}": {"index": i} for i in range(100)})

        run_async(setup())

        def concurrent_reads():
            async def _reads():
                async with AsyncNanaSQLite(db_path) as db:
                    tasks = [db.aget(f"key_{i}") for i in range(10)]
                    return await asyncio.gather(*tasks)

            return run_async(_reads())

        benchmark(concurrent_reads)

    def test_async_concurrent_reads_100(self, benchmark, db_path):
        """並行読み込み（100件同時）"""
        from nanasqlite import AsyncNanaSQLite

        # データ準備
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.batch_update({f"key_{i}": {"index": i} for i in range(100)})

        run_async(setup())

        def concurrent_reads():
            async def _reads():
                async with AsyncNanaSQLite(db_path) as db:
                    tasks = [db.aget(f"key_{i}") for i in range(100)]
                    return await asyncio.gather(*tasks)

            return run_async(_reads())

        benchmark(concurrent_reads)

    def test_async_concurrent_writes_10(self, benchmark, db_path):
        """並行書き込み（10件同時）"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def concurrent_writes():
            async def _writes():
                async with AsyncNanaSQLite(db_path) as db:
                    base = counter[0] * 10
                    tasks = [db.aset(f"cw_{base + i}", {"value": i}) for i in range(10)]
                    await asyncio.gather(*tasks)
                    counter[0] += 1

            run_async(_writes())

        benchmark(concurrent_writes)

    def test_async_concurrent_writes_100(self, benchmark, db_path):
        """並行書き込み（100件同時）"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def concurrent_writes():
            async def _writes():
                async with AsyncNanaSQLite(db_path) as db:
                    base = counter[0] * 100
                    tasks = [db.aset(f"cw_{base + i}", {"value": i}) for i in range(100)]
                    await asyncio.gather(*tasks)
                    counter[0] += 1

            run_async(_writes())

        benchmark(concurrent_writes)

    def test_async_concurrent_mixed_50(self, benchmark, db_path):
        """並行混合操作（読み書き各25件）"""
        from nanasqlite import AsyncNanaSQLite

        # データ準備
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.batch_update({f"read_key_{i}": {"index": i} for i in range(25)})

        run_async(setup())

        counter = [0]

        def concurrent_mixed():
            async def _mixed():
                async with AsyncNanaSQLite(db_path) as db:
                    base = counter[0] * 25
                    read_tasks = [db.aget(f"read_key_{i}") for i in range(25)]
                    write_tasks = [db.aset(f"write_key_{base + i}", {"value": i}) for i in range(25)]
                    await asyncio.gather(*(read_tasks + write_tasks))
                    counter[0] += 1

            run_async(_mixed())

        benchmark(concurrent_mixed)


# ==================== Async SQL Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncSQLOperationsBenchmarks:
    """非同期SQL操作のベンチマーク"""

    def test_async_create_table(self, benchmark, db_path):
        """非同期テーブル作成"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def create_table():
            async def _create():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.create_table(
                        f"test_table_{counter[0]}", {"id": "INTEGER PRIMARY KEY", "name": "TEXT", "age": "INTEGER"}
                    )
                    counter[0] += 1

            run_async(_create())

        benchmark(create_table)

    def test_async_sql_insert(self, benchmark, db_path):
        """非同期SQL INSERT"""
        from nanasqlite import AsyncNanaSQLite

        # テーブル作成
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table(
                    "users", {"id": "INTEGER PRIMARY KEY AUTOINCREMENT", "name": "TEXT", "age": "INTEGER"}
                )

        run_async(setup())

        counter = [0]

        def insert_single():
            async def _insert():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.sql_insert("users", {"name": f"User{counter[0]}", "age": 25})
                    counter[0] += 1

            run_async(_insert())

        benchmark(insert_single)

    def test_async_sql_update(self, benchmark, async_db_instance):
        """非同期SQL UPDATE"""

        # データ準備
        async def setup():
            await async_db_instance.create_table("users_upd", {"id": "INTEGER", "name": "TEXT", "age": "INTEGER"})
            for i in range(100):
                await async_db_instance.sql_insert("users_upd", {"id": i, "name": f"User{i}", "age": 25})

        run_async(setup())

        counter = [0]

        def update_single():
            async def _update():
                await async_db_instance.sql_update("users_upd", {"age": 26}, "id = ?", (counter[0] % 100,))
                counter[0] += 1

            run_async(_update())

        benchmark(update_single)

    def test_async_sql_delete(self, benchmark, async_db_instance):
        """非同期SQL DELETE"""
        counter = [0]

        def delete_op():
            async def _delete():
                # テーブル作成はこの操作に含まれても良いとするが、
                # 削除そのものを測るならテーブル作成は外出しした方が良い。
                # しかし動的にテーブル名を変えないと前回の残りがある。
                table = f"del_test_{counter[0]}"
                await async_db_instance.create_table(table, {"id": "INTEGER", "name": "TEXT"})
                await async_db_instance.sql_insert(table, {"id": 1, "name": "Test"})
                await async_db_instance.sql_delete(table, "id = ?", (1,))
                counter[0] += 1

            run_async(_delete())

        benchmark(delete_op)

    def test_async_query_simple(self, benchmark, async_db_instance):
        """非同期シンプルクエリ"""

        # データ準備
        async def setup():
            await async_db_instance.create_table("items_q", {"id": "INTEGER", "name": "TEXT", "value": "INTEGER"})
            data = [{"id": i, "name": f"Item{i}", "value": i % 100} for i in range(1000)]
            # batch_updateはdict用なのでSQLテーブルには直接使えないかもしれないが、
            # queryのテストなので準備は一括で行いたい。
            for i in range(1000):
                await async_db_instance.sql_insert("items_q", data[i])

        run_async(setup())

        def query_simple():
            async def _query():
                return await async_db_instance.query(
                    "items_q", columns=["id", "name"], where="value > ?", parameters=(50,), limit=10
                )

            return run_async(_query())

        benchmark(query_simple)

    def test_async_fetch_one(self, benchmark, db_path):
        """非同期fetch_one"""
        from nanasqlite import AsyncNanaSQLite

        # データ準備
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("items", {"id": "INTEGER", "value": "TEXT"})
                for i in range(1000):
                    await db.sql_insert("items", {"id": i, "value": f"data{i}"})

        run_async(setup())

        def fetch_one():
            async def _fetch():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.fetch_one("SELECT * FROM items WHERE id = ?", (500,))

            return run_async(_fetch())

        benchmark(fetch_one)

    def test_async_fetch_all_1000(self, benchmark, db_path):
        """非同期fetch_all（1000件）"""
        from nanasqlite import AsyncNanaSQLite

        # データ準備
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("items", {"id": "INTEGER", "value": "TEXT"})
                for i in range(1000):
                    await db.sql_insert("items", {"id": i, "value": f"data{i}"})

        run_async(setup())

        def fetch_all():
            async def _fetch():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.fetch_all("SELECT * FROM items")

            return run_async(_fetch())

        benchmark(fetch_all)

    def test_async_execute_raw(self, benchmark, db_path):
        """非同期直接SQL実行"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("exec_test", {"id": "INTEGER", "value": "TEXT"})

        run_async(setup())

        counter = [0]

        def execute_raw():
            async def _exec():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.execute(
                        "INSERT INTO exec_test (id, value) VALUES (?, ?)", (counter[0], f"val{counter[0]}")
                    )
                    counter[0] += 1

            run_async(_exec())

        benchmark(execute_raw)


# ==================== Async Schema Operations Benchmarks ====================





# ==================== Async Batch Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncBatchOperationsBenchmarks:
    """非同期バッチ操作のベンチマーク"""

    def test_async_batch_delete_100(self, benchmark, db_path):
        """非同期バッチ削除（100件）"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def batch_delete():
            async def _delete():
                async with AsyncNanaSQLite(db_path) as db:
                    keys = [f"bd_{counter[0]}_{i}" for i in range(100)]
                    await db.batch_update({k: {"value": i} for i, k in enumerate(keys)})
                    await db.batch_delete(keys)
                    counter[0] += 1

            run_async(_delete())

        benchmark(batch_delete)

    def test_async_update_dict(self, benchmark, db_path):
        """非同期update()複数キー更新"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def update_op():
            async def _update():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.aupdate({f"up_{counter[0]}_{i}": f"value_{i}" for i in range(50)})
                    counter[0] += 1

            run_async(_update())

        benchmark(update_op)

    def test_async_clear(self, benchmark, db_path):
        """非同期clear()全削除"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def clear_op():
            async def _clear():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.batch_update({f"clear_{counter[0]}_{i}": {"v": i} for i in range(100)})
                    await db.aclear()
                    counter[0] += 1

            run_async(_clear())

        benchmark(clear_op)


# ==================== Async Pydantic Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncPydanticOperationsBenchmarks:
    """非同期Pydantic操作のベンチマーク"""

    def test_async_set_model(self, benchmark, db_path):
        """非同期set_model()モデル保存"""
        try:
            from pydantic import BaseModel
        except ImportError:
            pytest.skip("pydantic not installed")

        from nanasqlite import AsyncNanaSQLite

        class TestUser(BaseModel):
            name: str
            age: int
            email: str

        counter = [0]

        def set_model():
            async def _set():
                async with AsyncNanaSQLite(db_path) as db:
                    user = TestUser(name=f"User{counter[0]}", age=25, email=f"user{counter[0]}@example.com")
                    await db.set_model(f"user_{counter[0]}", user)
                    counter[0] += 1

            run_async(_set())

        benchmark(set_model)

    def test_async_get_model(self, benchmark, db_path):
        """非同期get_model()モデル取得"""
        try:
            from pydantic import BaseModel
        except ImportError:
            pytest.skip("pydantic not installed")

        from nanasqlite import AsyncNanaSQLite

        class TestUser(BaseModel):
            name: str
            age: int
            email: str

        # 事前にモデルを保存
        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                for i in range(100):
                    user = TestUser(name=f"User{i}", age=25, email=f"user{i}@example.com")
                    await db.set_model(f"model_user_{i}", user)

        run_async(setup())

        counter = [0]

        def get_model():
            async def _get():
                async with AsyncNanaSQLite(db_path) as db:
                    result = await db.get_model(f"model_user_{counter[0] % 100}", TestUser)
                    counter[0] += 1
                    return result

            return run_async(_get())

        benchmark(get_model)


# ==================== Async Utility Operations Benchmarks ====================





if __name__ == "__main__":
    pytest.main([__file__, "-v", "--benchmark-only"])


# ==================== Async Encryption Benchmarks ====================

@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncEncryptionBenchmarks:
    """非同期暗号化パフォーマンスのベンチマーク"""

    @pytest.mark.parametrize("mode", ["aes-gcm", "chacha20"])
    def test_async_write_encryption(self, benchmark, db_path, mode):
        """非同期暗号化書き込み（スレッドプールオフロードのコスト含む）"""
        from cryptography.hazmat.primitives.ciphers.aead import AESGCM, ChaCha20Poly1305

        from nanasqlite import AsyncNanaSQLite

        key = None
        enc_mode = "aes-gcm"

        if mode == "aes-gcm":
            key = AESGCM.generate_key(bit_length=256)
        elif mode == "chacha20":
            key = ChaCha20Poly1305.generate_key()
            enc_mode = "chacha20"

        data = {"v": "x" * 100}
        counter = [0]

        def write_encryption():
            async def _write():
                async with AsyncNanaSQLite(db_path, encryption_key=key, encryption_mode=enc_mode) as db:
                    await db.aset(f"k_{counter[0]}", data)
                    counter[0] += 1
            run_async(_write())

        benchmark(write_encryption)

    def test_async_read_encryption_uncached(self, benchmark, db_path):
        """非同期暗号化読み込み（キャッシュミス）"""
        from cryptography.hazmat.primitives.ciphers.aead import AESGCM

        from nanasqlite import AsyncNanaSQLite

        key = AESGCM.generate_key(bit_length=256)
        data = {"v": "x" * 1024}

        # Pre-fill
        async def setup():
            async with AsyncNanaSQLite(db_path, encryption_key=key) as db:
                 await db.aset("uncached_target", data)
        run_async(setup())

        def read_op():
            async def _read():
                 async with AsyncNanaSQLite(db_path, encryption_key=key) as db:
                      # New connection implies empty cache (persistence TTL aside)
                      return await db.aget("uncached_target")
            run_async(_read())

        benchmark(read_op)


# ==================== Async Mixed Benchmarks ====================

@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncMixedBenchmarks:
    """非同期 複合条件（暗号化＋キャッシュ＋並行）ベンチマーク"""

    def test_async_aes_concurrent_writes(self, benchmark, db_path):
        """AES暗号化有効時の並行書き込み"""
        from cryptography.hazmat.primitives.ciphers.aead import AESGCM

        from nanasqlite import AsyncNanaSQLite

        key = AESGCM.generate_key(bit_length=256)
        counter = [0]

        def concurrent_writes():
            async def _writes():
                 async with AsyncNanaSQLite(db_path, encryption_key=key) as db:
                      base = counter[0] * 10
                      tasks = [db.aset(f"cw_{base + i}", {"v": i}) for i in range(10)]
                      await asyncio.gather(*tasks)
                      counter[0] += 1
            run_async(_writes())

        benchmark(concurrent_writes)


# ==================== Async Cache Strategy Benchmarks ====================

@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncCacheStrategyBenchmarks:
    """非同期キャッシュ戦略ベンチマーク"""

    @pytest.fixture
    def async_cache_dbs(self, db_path):
        import os
        import shutil

        from nanasqlite import CacheType


        base_dir = os.path.dirname(db_path)
        cache_dir = os.path.join(base_dir, "async_cache_bench")
        if os.path.exists(cache_dir):
            shutil.rmtree(cache_dir)
        os.makedirs(cache_dir, exist_ok=True)

        strategies = {
            "unbounded": (CacheType.UNBOUNDED, None),
            "lru": (CacheType.LRU, 1000),
            "fifo": (CacheType.UNBOUNDED, 1000),
            "ttl": (CacheType.TTL, 3600),
        }

        yield (cache_dir, strategies)

        # Cleanup
        if os.path.exists(cache_dir):
            shutil.rmtree(cache_dir)

    @pytest.mark.parametrize("strategy_name", ["unbounded", "lru", "fifo", "ttl"])
    def test_async_cache_write_100(self, benchmark, async_cache_dbs, strategy_name):
        """非同期キャッシュ書き込み性能"""
        cache_dir, strategies = async_cache_dbs
        strategy, size = strategies[strategy_name]

        kw = {}
        if strategy_name == "ttl":
            kw["cache_ttl"] = size
        elif size:
            kw["cache_size"] = size

        db_path = os.path.join(cache_dir, f"{strategy_name}_write.db")

        from nanasqlite import AsyncNanaSQLite  # import here to be safe

        def write_op():
            async def _write():
                async with AsyncNanaSQLite(db_path, cache_strategy=strategy, **kw) as db:
                    for i in range(100):
                        await db.aset(f"w_{i}", i)
            run_async(_write())

        benchmark(write_op)

    @pytest.mark.parametrize("strategy_name", ["unbounded", "lru", "fifo", "ttl"])
    def test_async_cache_read_hit(self, benchmark, async_cache_dbs, strategy_name):
        """非同期キャッシュ読み込み性能（ヒット）"""
        cache_dir, strategies = async_cache_dbs
        strategy, size = strategies[strategy_name]

        kw = {}
        if strategy_name == "ttl":
            kw["cache_ttl"] = size
        elif size:
            kw["cache_size"] = size

        db_path = os.path.join(cache_dir, f"{strategy_name}_read.db")

        from nanasqlite import AsyncNanaSQLite

        # Pre-fill
        async def setup():
            async with AsyncNanaSQLite(db_path, cache_strategy=strategy, **kw) as db:
                for i in range(100):
                    await db.aset(f"r_{i}", i)
        run_async(setup())

        def read_op():
            async def _read():
                 async with AsyncNanaSQLite(db_path, cache_strategy=strategy, **kw) as db:
                    for i in range(100):
                        await db.aget(f"r_{i}")
            run_async(_read())

        benchmark(read_op)

    def test_async_lru_eviction(self, benchmark, async_cache_dbs):
        """非同期LRU退避コスト"""
        cache_dir, _ = async_cache_dbs
        db_path = os.path.join(cache_dir, "lru_evict.db")

        from nanasqlite import AsyncNanaSQLite, CacheType

        # Pre-fill 10 items (size 10)
        async def setup():
             async with AsyncNanaSQLite(db_path, cache_strategy=CacheType.LRU, cache_size=10) as db:
                 for i in range(10):
                     await db.aset(f"init_{i}", i)
        run_async(setup())

        counter = [0]
        def eviction_op():
            async def _evict():
                 async with AsyncNanaSQLite(db_path, cache_strategy=CacheType.LRU, cache_size=10) as db:
                      await db.aset(f"new_{counter[0]}", counter[0])
                      counter[0] += 1
            run_async(_evict())

        benchmark(eviction_op)

    def test_async_ttl_expiry_check(self, benchmark, tmp_path):
        """TTL有効期限チェックのオーバーヘッド（非同期）"""
        from nanasqlite import AsyncNanaSQLite, CacheType

        db_path = str(tmp_path / "async_ttl_check.db")

        async def setup():
             async with AsyncNanaSQLite(db_path, cache_strategy=CacheType.TTL, cache_ttl=60) as db:
                 await db.aset("target", "value")
        run_async(setup())

        def read_op():
            async def _read():
                 async with AsyncNanaSQLite(db_path, cache_strategy=CacheType.TTL, cache_ttl=60) as db:
                     return await db.aget("target")
            return run_async(_read())

        benchmark(read_op)


# ==================== Async DDL Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncDDLOperationsBenchmarks:
    """非同期DDL操作のベンチマーク"""

    def test_async_create_index(self, benchmark, db_path):
        """create_index()インデックス作成"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
             async with AsyncNanaSQLite(db_path) as db:
                 await db.create_table("idx_create_test", {"id": "INTEGER", "name": "TEXT"})

        run_async(setup())
        counter = [0]

        def create_idx():
            async def _create():
                async with AsyncNanaSQLite(db_path) as db:
                    idx_name = f"idx_{counter[0]}"
                    await db.create_index(idx_name, "idx_create_test", ["name"], if_not_exists=True)
                    await db.drop_index(idx_name)  # clean up
            run_async(_create())
            counter[0] += 1

        benchmark(create_idx)

    def test_async_drop_table(self, benchmark, db_path):
        """drop_table()テーブル削除"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def drop_tbl():
            async def _drop():
                async with AsyncNanaSQLite(db_path) as db:
                    table_name = f"drop_test_{counter[0]}"
                    await db.create_table(table_name, {"id": "INTEGER"})
                    await db.drop_table(table_name)
            run_async(_drop())
            counter[0] += 1

        benchmark(drop_tbl)

    def test_async_drop_index(self, benchmark, db_path):
        """drop_index()インデックス削除"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("idx_test", {"id": "INTEGER", "name": "TEXT"})
        run_async(setup())
        counter = [0]

        def drop_idx():
            async def _drop():
                async with AsyncNanaSQLite(db_path) as db:
                    idx_name = f"idx_drop_{counter[0]}"
                    await db.create_index(idx_name, "idx_test", ["name"], if_not_exists=True)
                    await db.drop_index(idx_name)
            run_async(_drop())
            counter[0] += 1

        benchmark(drop_idx)

    def test_async_sql_delete(self, benchmark, db_path):
        """sql_delete()行削除"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("delete_test", {"id": "INTEGER", "name": "TEXT"})
                # Prepare data
                for i in range(1000):
                    await db.sql_insert("delete_test", {"id": i, "name": f"User{i}"})
        run_async(setup())

        counter = [0]

        def delete_op():
            async def _delete():
                async with AsyncNanaSQLite(db_path) as db:
                    target_id = counter[0] % 1000
                    await db.sql_delete("delete_test", "id = ?", (target_id,))
                    # Re-insert
                    await db.sql_insert("delete_test", {"id": target_id, "name": f"User{counter[0]}"})
            run_async(_delete())
            counter[0] += 1

        benchmark(delete_op)


# ==================== Async Schema Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncSchemaOperationsBenchmarks:
    """非同期スキーマ操作のベンチマーク"""

    def test_async_table_exists(self, benchmark, db_path):
        """table_exists()テーブル存在確認"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
             async with AsyncNanaSQLite(db_path) as db:
                 await db.create_table("exists_test", {"id": "INTEGER"})
        run_async(setup())

        def table_exists_op():
            async def _exists():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.table_exists("exists_test")
            return run_async(_exists())

        benchmark(table_exists_op)

    def test_async_list_tables(self, benchmark, db_path):
        """list_tables()テーブル一覧"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
             async with AsyncNanaSQLite(db_path) as db:
                 for i in range(20):
                     await db.create_table(f"list_test_{i}", {"id": "INTEGER"})
        run_async(setup())

        def list_tables_op():
            async def _list():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.list_tables()
            return run_async(_list())

        benchmark(list_tables_op)


# ==================== Async Utility Operations Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncUtilityOperationsBenchmarks:
    """非同期ユーティリティ操作のベンチマーク"""

    def test_async_get_fresh(self, benchmark, db_path):
        """get_fresh()キャッシュバイパス読み込み"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
             async with AsyncNanaSQLite(db_path) as db:
                 await db.aset("target_key", {"data": "value", "number": 123})
        run_async(setup())

        def get_fresh_op():
            async def _get():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.get_fresh("target_key")
            return run_async(_get())

        benchmark(get_fresh_op)

    def test_async_batch_delete(self, benchmark, db_path):
        """batch_delete()一括削除"""
        from nanasqlite import AsyncNanaSQLite

        counter = [0]

        def batch_delete_op():
            async def _op():
                async with AsyncNanaSQLite(db_path) as db:
                    # Create data
                    keys = [f"batch_del_{counter[0]}_{i}" for i in range(100)]
                    data = {k: {"value": i} for i, k in enumerate(keys)}
                    await db.batch_update(data)
                    # Delete
                    await db.batch_delete(keys)
            run_async(_op())
            counter[0] += 1

        benchmark(batch_delete_op)

    def test_async_vacuum(self, benchmark, db_path):
        """vacuum()最適化"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                for i in range(100):
                    await db.aset(f"vac_key_{i}", {"data": "x" * 100})
                for i in range(50):
                    await db.adelete(f"vac_key_{i}")
        run_async(setup())

        counter = [0]

        def vacuum_op():
            async def _vac():
                async with AsyncNanaSQLite(db_path) as db:
                    # Churn data
                    await db.aset(f"vac_extra_{counter[0]}", {"data": "y" * 100})
                    if counter[0] > 0:
                         await db.adelete(f"vac_extra_{counter[0] - 1}")
                    await db.vacuum()
            run_async(_vac())
            counter[0] += 1

        benchmark(vacuum_op)

    def test_async_execute_raw(self, benchmark, db_path):
        """execute()直接SQL実行"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("exec_test", {"id": "INTEGER", "value": "TEXT"})
        run_async(setup())

        counter = [0]

        def execute_op():
            async def _exec():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.execute(
                        "INSERT INTO exec_test (id, value) VALUES (?, ?)",
                        (counter[0], f"val{counter[0]}")
                    )
            run_async(_exec())
            counter[0] += 1

        benchmark(execute_op)

    def test_async_execute_many(self, benchmark, db_path):
        """execute_many()一括SQL実行"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("exec_many_test", {"id": "INTEGER", "value": "TEXT"})
        run_async(setup())

        counter = [0]

        def execute_many_op():
            async def _exec():
                async with AsyncNanaSQLite(db_path) as db:
                    base = counter[0] * 100
                    params = [(base + i, f"val{i}") for i in range(100)]
                    await db.execute_many(
                        "INSERT INTO exec_many_test (id, value) VALUES (?, ?)",
                        params
                    )
            run_async(_exec())
            counter[0] += 1

        benchmark(execute_many_op)

    def test_async_transaction_context(self, benchmark, db_path):
        """transaction()コンテキストマネージャ"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("logs", {"id": "INTEGER", "message": "TEXT"})
        run_async(setup())

        counter = [0]

        def transaction_op():
            async def _trans():
                async with AsyncNanaSQLite(db_path) as db:
                    async with db.transaction():
                        await db.sql_insert("logs", {"id": counter[0], "message": f"Log{counter[0]}"})
            run_async(_trans())
            counter[0] += 1

        benchmark(transaction_op)

    def test_async_count(self, benchmark, db_path):
        """count()レコード数取得"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.create_table("items", {"id": "INTEGER", "value": "INTEGER"})
                for i in range(100):
                    await db.sql_insert("items", {"id": i, "value": i})
        run_async(setup())

        def count_records():
            async def _count():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.count("items", "value > ?", (50,))
            return run_async(_count())

        benchmark(count_records)

    def test_async_refresh_all(self, benchmark, db_path):
        """非同期refresh()全件"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.aset("key1", "value1")
        run_async(setup())

        def refresh_op():
            async def _refresh():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.arefresh()
            run_async(_refresh())

        benchmark(refresh_op)

    def test_async_load_all(self, benchmark, db_path):
        """非同期load_all()一括ロード"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.abatch_update({f"load_key_{i}": {"index": i} for i in range(1000)})
        run_async(setup())

        def load_all():
            async def _load():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.aload_all()
            run_async(_load())

        benchmark(load_all)

    def test_async_copy(self, benchmark, db_path):
        """非同期copy()浅いコピー"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                 await db.aset("k", "v")
        run_async(setup())

        def copy_op():
            async def _copy():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.copy()
            return run_async(_copy())

        benchmark(copy_op)

    def test_async_is_cached(self, benchmark, db_path):
        """非同期is_cached()"""
        from nanasqlite import AsyncNanaSQLite

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                 await db.aset("key_0", "val")
                 await db.aget("key_0") # Ensure cached
        run_async(setup())

        def is_cached_op():
            async def _check():
                 async with AsyncNanaSQLite(db_path) as db:
                     return await db.is_cached("key_0")
            return run_async(_check())

        benchmark(is_cached_op)


# ==================== Async v2 Architecture Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncV2ArchitectureBenchmarks:
    """非同期v2アーキテクチャ（Write-Back Cache）のベンチマーク"""

    @pytest.fixture
    def async_v2_dbs(self, tmp_path):
        import os

        from nanasqlite import AsyncNanaSQLite

        base_dir = tmp_path / "async_v2_bench"
        base_dir.mkdir()

        # Suppress multiprocess warning in test environment
        os.environ["NANASQLITE_SUPPRESS_MP_WARNING"] = "1"

        dbs = {}
        modes = ["immediate", "count", "time", "manual"]

        for mode in modes:
            kwargs = {"v2_mode": True, "flush_mode": mode}
            if mode == "immediate":
                kwargs["flush_interval"] = 1.0
            elif mode == "count":
                kwargs["flush_count"] = 100
            elif mode == "time":
                kwargs["flush_interval"] = 0.1

            dbs[mode] = AsyncNanaSQLite(str(base_dir / f"async_v2_{mode}.db"), **kwargs)

        yield dbs

        for db in dbs.values():
            with contextlib.suppress(Exception):
                run_async(db.close())

    @pytest.mark.parametrize("mode", ["immediate", "count", "time", "manual"])
    def test_async_v2_write_1000(self, benchmark, async_v2_dbs, mode):
        """v2モードごとの非同期書き込み性能 (100件連続)"""
        db = async_v2_dbs[mode]

        def write_op():
            async def _write():
                for i in range(100):
                    await db.aset(f"w_{i}", i)
            run_async(_write())

        benchmark(write_op)

    @pytest.mark.parametrize("mode", ["immediate", "count", "time", "manual"])
    def test_async_v2_read_hit(self, benchmark, async_v2_dbs, mode):
        """v2モードごとの非同期読み込み性能 (キャッシュヒット)"""
        db = async_v2_dbs[mode]
        # Setup data
        async def setup():
            for i in range(100):
                await db.aset(f"r_{i}", i)
        run_async(setup())

        def read_op():
            async def _read():
                for i in range(100):
                    await db.aget(f"r_{i}")
            run_async(_read())

        benchmark(read_op)

    def test_async_v2_batch_write_1000(self, benchmark, async_v2_dbs):
        """v2モード (count) での非同期バッチ書き込み性能"""
        db = async_v2_dbs["count"]

        def batch_write():
            async def _batch():
                data = {f"batch_{i}": {"index": i} for i in range(1000)}
                await db.abatch_update(data)
            run_async(_batch())

        benchmark(batch_write)

    def test_async_v2_upsert(self, benchmark, async_v2_dbs):
        """v2モードごとの非同期 upsert パフォーマンス"""
        db = async_v2_dbs["count"]
        counter = [0]

        def upsert_op():
            async def _upsert():
                await db.aupsert(f"u_{counter[0]}", counter[0])
                counter[0] += 1
            run_async(_upsert())

        benchmark(upsert_op)

    def test_async_v2_dlq_ops(self, benchmark, async_v2_dbs):
        """非同期 get_dlq() のオーバーヘッド"""
        db = async_v2_dbs["manual"]

        def dlq_op():
            async def _dlq():
                return await db.aget_dlq()
            return run_async(_dlq())

        benchmark(dlq_op)


# ==================== Async Backup & Restore Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncBackupRestoreBenchmarks:
    """非同期バックアップとリストアのベンチマーク"""

    def test_async_backup_1000(self, benchmark, db_path, tmp_path):
        """非同期バックアップ (1000件)"""
        from nanasqlite import AsyncNanaSQLite

        backup_path = str(tmp_path / "async_backup.db")

        async def setup():
            async with AsyncNanaSQLite(db_path) as db:
                await db.abatch_update({f"k_{i}": i for i in range(1000)})
        run_async(setup())

        def backup_op():
            async def _backup():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.abackup(backup_path)
            run_async(_backup())

        benchmark(backup_op)

    def test_async_restore_1000(self, benchmark, db_path, tmp_path):
        """非同期リストア (1000件)"""
        from nanasqlite import AsyncNanaSQLite

        source_path = str(tmp_path / "async_restore_src.db")

        async def setup():
            async with AsyncNanaSQLite(source_path) as db:
                await db.abatch_update({f"k_{i}": i for i in range(1000)})
        run_async(setup())

        def restore_op():
            async def _restore():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.arestore(source_path)
            run_async(_restore())

        benchmark(restore_op)


# ==================== Async Extended Utility Benchmarks ====================


@pytest.mark.skipif(not pytest_benchmark_available, reason="pytest-benchmark not installed")
class TestAsyncExtendedBenchmarks:
    """非同期スキーマ操作やユーティリティの追加ベンチマーク"""

    def test_async_pragma_read(self, benchmark, db_path):
        """非同期 PRAGMA 取得"""
        from nanasqlite import AsyncNanaSQLite

        def pragma_op():
            async def _pragma():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.apragma("journal_mode")
            return run_async(_pragma())

        benchmark(pragma_op)

    def test_async_get_table_schema(self, benchmark, db_path):
        """非同期 get_table_schema 取得"""
        from nanasqlite import AsyncNanaSQLite

        def schema_op():
            async def _schema():
                async with AsyncNanaSQLite(db_path) as db:
                    return await db.aget_table_schema()
            return run_async(_schema())

        benchmark(schema_op)

    def test_async_alter_table_add_column(self, benchmark, db_path):
        """非同期 alter_table_add_column 実行"""
        from nanasqlite import AsyncNanaSQLite
        counter = [0]

        def alter_op():
            async def _alter():
                async with AsyncNanaSQLite(db_path) as db:
                    await db.aalter_table_add_column("data", f"new_async_col_{counter[0]}", "TEXT")
                    counter[0] += 1
            run_async(_alter())

        benchmark(alter_op)

