"""
Unit tests for Falcorn Python bindings
"""

import pytest
from _falcorn import (
    ControlClient,
    DEFAULT_CONTROL_SOCKET,
    DEFAULT_LOG_SOCKET,
    FalcornServer,
    LoggingClient,
    PLUGIN_FILTER_ACCESS_LOG,
    PLUGIN_FILTER_ALL,
    PLUGIN_FILTER_LOG_MESSAGE,
    PLUGIN_FILTER_METRICS,
    PyServerConfig,
    WorkerClass,
)


def test_worker_class():
    """Test WorkerClass enum"""
    sync = WorkerClass("sync")
    async_wc = WorkerClass("async")

    assert str(sync) == "sync"
    assert str(async_wc) == "async"

    # Test invalid
    with pytest.raises(ValueError):
        WorkerClass("invalid")


def test_plugin_constants():
    assert isinstance(DEFAULT_LOG_SOCKET, str)
    assert isinstance(DEFAULT_CONTROL_SOCKET, str)
    assert isinstance(PLUGIN_FILTER_LOG_MESSAGE, int)
    assert isinstance(PLUGIN_FILTER_ACCESS_LOG, int)
    assert isinstance(PLUGIN_FILTER_METRICS, int)
    assert isinstance(PLUGIN_FILTER_ALL, int)


def test_plugin_clients_fail_without_server(tmp_path):
    missing_log_socket = str(tmp_path / "missing-log.sock")
    missing_control_socket = str(tmp_path / "missing-control.sock")

    with pytest.raises(RuntimeError):
        LoggingClient(socket=missing_log_socket)

    with pytest.raises(RuntimeError):
        ControlClient(socket=missing_control_socket)


def test_server_config_creation():
    """Test PyServerConfig creation"""
    config = PyServerConfig("app", "application")

    assert config.app_module == "app"
    assert config.app_callable == "application"
    assert config.host == "127.0.0.1"
    assert config.port == 8000
    assert config.worker_class == WorkerClass.Sync
    assert config.backlog > 0
    assert config.strict_http is False


def test_server_config_validation():
    """Test configuration validation"""
    config = PyServerConfig("app", "application")

    # Valid config should not raise
    config.validate()

    # Invalid port
    config.port = 0
    with pytest.raises(ValueError):
        config.validate()


def test_server_config_full_overrides():
    """Test full config surface is exposed and mutable."""
    cfg = PyServerConfig("app", "application")

    cfg.host = "0.0.0.0"
    cfg.port = 9000
    cfg.backlog = 4096
    cfg.workers = 2
    cfg.h2c_enabled = True
    cfg.strict_http = True
    cfg.max_requests = 10
    cfg.max_requests_jitter = 3
    cfg.buffer_size = 8192
    cfg.keepalive_timeout = 10
    cfg.max_connections = 4096
    cfg.sync_handler_threads = 2
    cfg.sync_conn_queue_capacity = 128
    cfg.async_worker_threads = 2
    cfg.async_max_blocking_threads = 16
    cfg.asgi_event_loop = "asyncio"
    cfg.asgi_event_loop_fallback = True
    cfg.asgi_submit_timeout_ms = 1000
    cfg.asgi_scheduler = "task"
    cfg.asgi_max_inflight = 128
    cfg.asgi_send_pool_size = 256
    cfg.log_stdout = True
    cfg.log_level = "DEBUG"
    cfg.access_log_format = "%(h)s %(r)s"
    cfg.access_log = "access.log"
    cfg.error_log = "error.log"
    cfg.plugin_socket = "/tmp/falcorn.sock"
    cfg.plugin_auth_token = "token"
    cfg.plugin_drop_policy = "drop_oldest"
    cfg.plugin_max_lagged_events = 512
    cfg.plugin_write_timeout_ms = 250
    cfg.plugin_bus_capacity = 1024
    cfg.plugin_max_clients = 64
    cfg.plugin_subscribe_timeout_ms = 2000
    cfg.plugin_auth_fail_window_secs = 30
    cfg.plugin_auth_fail_max_attempts = 3
    cfg.plugin_acl_mode = "same_user"
    cfg.plugin_socket_mode = 0o660
    cfg.metrics_interval_ms = 3000
    cfg.metrics_workers_enabled = True
    cfg.metrics_os_enabled = False
    cfg.metrics_percentiles_enabled = True
    cfg.metrics_top_errors_limit = 5
    cfg.control_socket = "/tmp/falcorn-control.sock"
    cfg.control_auth_token = "control-token"
    cfg.control_acl_mode = "same_user"
    cfg.control_socket_mode = 0o660
    cfg.ssl_enabled = False
    cfg.ssl_certfile = None
    cfg.ssl_keyfile = None

    assert cfg.host == "0.0.0.0"
    assert cfg.port == 9000
    assert cfg.backlog == 4096
    assert cfg.workers == 2
    assert cfg.h2c_enabled is True
    assert cfg.strict_http is True
    assert cfg.max_requests == 10
    assert cfg.max_requests_jitter == 3
    assert cfg.buffer_size == 8192
    assert cfg.keepalive_timeout == 10
    assert cfg.max_connections == 4096
    assert cfg.sync_handler_threads == 2
    assert cfg.sync_conn_queue_capacity == 128
    assert cfg.async_worker_threads == 2
    assert cfg.async_max_blocking_threads == 16
    assert cfg.asgi_event_loop == "asyncio"
    assert cfg.asgi_event_loop_fallback is True
    assert cfg.asgi_submit_timeout_ms == 1000
    assert cfg.asgi_scheduler == "task"
    assert cfg.asgi_max_inflight == 128
    assert cfg.asgi_send_pool_size == 256
    assert cfg.log_stdout is True
    assert cfg.log_level == "DEBUG"
    assert cfg.access_log_format == "%(h)s %(r)s"
    assert cfg.access_log == "access.log"
    assert cfg.error_log == "error.log"
    assert cfg.plugin_socket == "/tmp/falcorn.sock"
    assert cfg.plugin_auth_token == "token"
    assert cfg.plugin_drop_policy == "drop_oldest"
    assert cfg.plugin_max_lagged_events == 512
    assert cfg.plugin_write_timeout_ms == 250
    assert cfg.plugin_bus_capacity == 1024
    assert cfg.plugin_max_clients == 64
    assert cfg.plugin_subscribe_timeout_ms == 2000
    assert cfg.plugin_auth_fail_window_secs == 30
    assert cfg.plugin_auth_fail_max_attempts == 3
    assert cfg.plugin_acl_mode == "same_user"
    assert cfg.plugin_socket_mode == 0o660
    assert cfg.metrics_interval_ms == 3000
    assert cfg.metrics_workers_enabled is True
    assert cfg.metrics_os_enabled is False
    assert cfg.metrics_percentiles_enabled is True
    assert cfg.metrics_top_errors_limit == 5
    assert cfg.control_socket == "/tmp/falcorn-control.sock"
    assert cfg.control_auth_token == "control-token"
    assert cfg.control_acl_mode == "same_user"
    assert cfg.control_socket_mode == 0o660


def test_server_config_worker_count():
    """Test worker count auto-detection"""
    config = PyServerConfig("app", "application")
    config.workers = None

    # Should auto-detect
    count = config.get_worker_count()
    assert count > 0


def test_server_creation():
    """Test FalcornServer creation"""

    server = FalcornServer("app", "application")

    assert server is not None

    # Check status
    status = server.status()
    assert "Falcorn Server" in status


def test_server_from_config():
    """Test server creation from config"""

    config = PyServerConfig("app", "application")
    config.workers = 4

    server = FalcornServer.from_config(config)

    assert server is not None
    retrieved_config = server.get_config()
    assert retrieved_config.workers == 4


def test_server_setters():
    """Test server setter methods"""

    server = FalcornServer("app", "application")

    # Set worker class
    server.set_worker_class("async")
    config = server.get_config()
    assert config.worker_class == WorkerClass.Async

    # Set timeout
    server.set_timeout(60)
    config = server.get_config()
    assert config.worker_timeout == 60

    # Set log level
    server.set_log_level("DEBUG")
    config = server.get_config()
    assert config.log_level == "DEBUG"

    # Add pythonpath
    server.add_pythonpath("./src")
    config = server.get_config()
    assert "./src" in config.pythonpath


def test_server_invalid_setters():
    """Test invalid setter values"""

    server = FalcornServer("app", "application")

    # Invalid worker class
    with pytest.raises(ValueError):
        server.set_worker_class("invalid")

    # Invalid timeout
    with pytest.raises(ValueError):
        server.set_timeout(0)

    # Invalid log level
    with pytest.raises(ValueError):
        server.set_log_level("INVALID")


def test_config_toml_roundtrip(tmp_path):
    """Test TOML save/load"""

    config = PyServerConfig("app", "application")
    config.workers = 8
    config.worker_class = WorkerClass.Async

    # Save
    toml_file = tmp_path / "test.toml"
    config.to_toml(str(toml_file))

    # Load
    loaded = PyServerConfig.from_toml(str(toml_file))

    assert loaded.workers == 8
    assert loaded.worker_class == WorkerClass.Async


def test_repr():
    """Test string representations"""

    server = FalcornServer("app", "application", port=8080)
    repr_str = repr(server)

    assert "FalcornServer" in repr_str
    assert "app:application" in repr_str
    assert "8080" in repr_str

    config = PyServerConfig("app", "application")
    config_repr = repr(config)

    assert "ServerConfig" in config_repr
