"""
Tests pour la gestion des erreurs Redis dans le scheduler.
"""

import pytest
from redis.exceptions import ConnectionError as RedisConnectionError
from redis.exceptions import RedisError, TimeoutError as RedisTimeoutError

from pricewatch.app.tasks.scheduler import RedisUnavailableError, ScrapingScheduler, check_redis_connection


class DummyRedisOk:
    def ping(self) -> bool:
        return True


class DummyRedisError:
    def __init__(self, exc: Exception) -> None:
        self._exc = exc

    def ping(self) -> None:
        raise self._exc


class DummyQueue:
    def __init__(self, name: str, connection=None) -> None:
        self.name = name
        self.connection = connection


class DummyScheduler:
    def __init__(self, queue=None, connection=None) -> None:
        self.queue = queue
        self.connection = connection

    def schedule(self, scheduled_time, func, args=None, kwargs=None, interval=None, repeat=None):
        return type("Job", (), {"id": "job-redis"})()


class FakeRedisConfig:
    def __init__(self, url: str) -> None:
        self.url = url


class FakeAppConfig:
    def __init__(self, redis_url: str) -> None:
        self.redis = FakeRedisConfig(redis_url)


def test_check_redis_connection_success(monkeypatch):
    """Ping OK retourne True."""
    monkeypatch.setattr("pricewatch.app.tasks.scheduler.redis.from_url", lambda url: DummyRedisOk())
    assert check_redis_connection("redis://localhost:6379/0") is True


def test_check_redis_connection_failure_connection(monkeypatch):
    """Ping en echec retourne False."""
    monkeypatch.setattr(
        "pricewatch.app.tasks.scheduler.redis.from_url",
        lambda url: DummyRedisError(RedisConnectionError("no")),
    )
    assert check_redis_connection("redis://localhost:6379/0") is False


def test_check_redis_connection_failure_timeout(monkeypatch):
    """Timeout Redis retourne False."""
    monkeypatch.setattr(
        "pricewatch.app.tasks.scheduler.redis.from_url",
        lambda url: DummyRedisError(RedisTimeoutError("timeout")),
    )
    assert check_redis_connection("redis://localhost:6379/0") is False


def test_scheduler_lazy_connection(monkeypatch):
    """La connexion Redis est lazy."""
    config = FakeAppConfig("redis://localhost:6379/0")
    monkeypatch.setattr("pricewatch.app.tasks.scheduler.redis.from_url", lambda url: DummyRedisOk())
    monkeypatch.setattr("pricewatch.app.tasks.scheduler.Queue", DummyQueue)
    monkeypatch.setattr("pricewatch.app.tasks.scheduler.Scheduler", DummyScheduler)

    scheduler = ScrapingScheduler(config=config)
    assert scheduler._redis is None

    _ = scheduler.queue
    assert scheduler._redis is not None


def test_scheduler_redis_connection_error(monkeypatch):
    """Une erreur de connexion leve RedisUnavailableError."""
    config = FakeAppConfig("redis://localhost:6379/0")

    def raise_connection(url):
        raise RedisConnectionError("no")

    monkeypatch.setattr("pricewatch.app.tasks.scheduler.redis.from_url", raise_connection)

    scheduler = ScrapingScheduler(config=config)
    with pytest.raises(RedisUnavailableError):
        _ = scheduler.queue


def test_scheduler_schedule_redis_error(monkeypatch):
    """Une erreur Redis leve RedisUnavailableError lors du schedule."""
    config = FakeAppConfig("redis://localhost:6379/0")

    monkeypatch.setattr(
        "pricewatch.app.tasks.scheduler.redis.from_url",
        lambda url: DummyRedisError(RedisError("boom")),
    )

    scheduler = ScrapingScheduler(config=config)
    with pytest.raises(RedisUnavailableError):
        scheduler.schedule_product("https://example.com/product", interval_hours=1)


def test_scheduler_enqueue_redis_error(monkeypatch):
    """Une erreur Redis leve RedisUnavailableError lors de l'enqueue."""
    config = FakeAppConfig("redis://localhost:6379/0")

    monkeypatch.setattr(
        "pricewatch.app.tasks.scheduler.redis.from_url",
        lambda url: DummyRedisError(RedisError("boom")),
    )

    scheduler = ScrapingScheduler(config=config)
    with pytest.raises(RedisUnavailableError):
        scheduler.enqueue_immediate("https://example.com/product")
