import importlib.util
import sys
import types
from pathlib import Path

from werkzeug.local import LocalProxy


ROOT = Path(__file__).resolve().parents[1]
GUNICORN_CONFIG_PATH = ROOT / "gunicorn.conf.py"


class _Log:
    def info(self, *_args, **_kwargs):
        return None

    def warning(self, *_args, **_kwargs):
        return None

    def exception(self, *_args, **_kwargs):
        return None


class _Server:
    log = _Log()


class _Worker:
    pid = 123


def _load_gunicorn_config():
    spec = importlib.util.spec_from_file_location(
        "gunicorn_conf_under_test",
        GUNICORN_CONFIG_PATH,
    )
    module = importlib.util.module_from_spec(spec)
    assert spec.loader is not None
    spec.loader.exec_module(module)
    return module


def test_post_fork_skips_request_bound_local_proxy(monkeypatch):
    config = _load_gunicorn_config()
    fake_module = types.ModuleType("services.fake_request_bound_module")

    def _missing_request_context():
        raise RuntimeError("Working outside of request context.")

    fake_module.request_bound = LocalProxy(_missing_request_context)
    monkeypatch.setitem(sys.modules, fake_module.__name__, fake_module)

    config.post_fork(_Server(), _Worker())


def test_post_fork_disposes_database_manager_instance_cache(monkeypatch):
    from sqlalchemy import create_engine

    config = _load_gunicorn_config()
    fake_module = types.ModuleType("database.manager")
    engine = create_engine("sqlite:///:memory:")
    before_pool = id(engine.pool)

    class FakeDatabaseManager:
        _instance_cache = {
            ("sqlite", "memory"): {
                "engine": engine,
                "Session": object(),
            }
        }

    fake_module.DatabaseManager = FakeDatabaseManager
    monkeypatch.setitem(sys.modules, fake_module.__name__, fake_module)

    config.post_fork(_Server(), _Worker())

    assert id(engine.pool) != before_pool


def test_gunicorn_disables_preload_for_hup_hot_reload():
    config = _load_gunicorn_config()

    assert config.preload_app is False


def test_gunicorn_starts_dashboard_cache_prewarm_thread():
    source = GUNICORN_CONFIG_PATH.read_text(encoding="utf-8")

    assert "def post_worker_init" in source
    assert "warm_full_dashboard_cache" in source
    assert "DASHBOARD_PREWARM_ON_WORKER_INIT" in source


def test_gunicorn_uses_thread_worker_for_health_resilience(monkeypatch):
    monkeypatch.delenv("GUNICORN_WORKER_CLASS", raising=False)
    monkeypatch.delenv("GUNICORN_THREADS", raising=False)

    config = _load_gunicorn_config()

    assert config.worker_class == "gthread"
    assert config.threads == 4


def test_gunicorn_thread_worker_can_be_overridden(monkeypatch):
    monkeypatch.setenv("GUNICORN_WORKER_CLASS", "sync")
    monkeypatch.setenv("GUNICORN_THREADS", "2")

    config = _load_gunicorn_config()

    assert config.worker_class == "sync"
    assert config.threads == 2
