"""Tests para cache_decorator."""

import asyncio
import sys
import os
import tempfile
import time

import pytest

sys.path.insert(0, os.path.dirname(__file__))
sys.path.insert(0, os.path.join(os.path.dirname(__file__), "..", "infra"))

from cache_decorator import cache_decorator
from cache_to_sqlite import cache_to_sqlite


@pytest.fixture
def store(tmp_path):
    return cache_to_sqlite(str(tmp_path / "test.db"))


def test_funcion_llamada_una_vez_segunda_vez_desde_cache(store):
    calls = []

    @cache_decorator(store, ttl=60)
    def compute(x: int) -> int:
        calls.append(x)
        return x * 10

    assert compute(5) == 50
    assert compute(5) == 50
    assert len(calls) == 1


def test_ttl_expirado_llama_de_nuevo(store):
    calls = []

    @cache_decorator(store, ttl=0.05)
    def work(n: int) -> int:
        calls.append(n)
        return n + 1

    work(3)
    time.sleep(0.1)
    work(3)
    assert len(calls) == 2


def test_key_fn_custom(store):
    calls = []

    def my_key_fn(func, args, kwargs):
        return f"custom:{args[0]}"

    @cache_decorator(store, ttl=60, key_fn=my_key_fn)
    def fn(x: int) -> str:
        calls.append(x)
        return f"result_{x}"

    fn(7)
    fn(7)
    assert len(calls) == 1


def test_argumentos_distintos_keys_distintas(store):
    calls = []

    @cache_decorator(store, ttl=60)
    def fn(x: int) -> int:
        calls.append(x)
        return x * 2

    fn(1)
    fn(2)
    fn(1)
    assert len(calls) == 2


def test_funciona_con_async(store):
    calls = []

    @cache_decorator(store, ttl=60)
    async def async_fn(x: int) -> int:
        calls.append(x)
        return x + 100

    async def run():
        r1 = await async_fn(5)
        r2 = await async_fn(5)
        return r1, r2

    r1, r2 = asyncio.run(run())
    assert r1 == 105
    assert r2 == 105
    assert len(calls) == 1
