"""Configuration contract tests."""

from __future__ import annotations

import pytest

from osm_lead_source_service.config import ENVIRONMENT_VARIABLES, AppConfig
from osm_lead_source_service.errors import InvalidConfiguration


def test_valid_configuration_is_immutable() -> None:
    config = AppConfig(environment="test", log_level="debug")
    assert config.read_only is True
    assert config.noco_write_enabled is False
    assert config.stale_deletion_enabled is False
    assert config.mcp_enabled is False
    assert config.scheduler_enabled is False
    with pytest.raises(AttributeError):
        config.environment = "changed"  # type: ignore[misc]


@pytest.mark.parametrize(
    "field_name",
    [
        "noco_write_enabled",
        "stale_deletion_enabled",
        "mcp_enabled",
    ],
)
def test_every_prohibited_capability_is_rejected(field_name: str) -> None:
    with pytest.raises(InvalidConfiguration, match=field_name):
        AppConfig(**{field_name: True})


def test_read_only_scheduler_can_be_enabled() -> None:
    config = AppConfig(scheduler_enabled=True)

    assert config.read_only is True
    assert config.scheduler_enabled is True
    assert config.noco_write_enabled is False


def test_read_only_cannot_be_disabled() -> None:
    with pytest.raises(InvalidConfiguration, match="read_only"):
        AppConfig(read_only=False)


@pytest.mark.parametrize("value", ["maybe", "", "2"])
def test_invalid_boolean_environment_value_is_rejected(value: str) -> None:
    with pytest.raises(InvalidConfiguration):
        AppConfig.from_env({ENVIRONMENT_VARIABLES["read_only"]: value})


@pytest.mark.parametrize(
    "field_name",
    [
        "noco_write_enabled",
        "stale_deletion_enabled",
        "mcp_enabled",
    ],
)
def test_environment_cannot_enable_prohibited_capability(field_name: str) -> None:
    variable_name = ENVIRONMENT_VARIABLES[field_name]
    with pytest.raises(InvalidConfiguration, match=field_name):
        AppConfig.from_env({variable_name: "true"})


def test_environment_scheduler_requires_separate_approval() -> None:
    requested = AppConfig.from_env({ENVIRONMENT_VARIABLES["scheduler_enabled"]: "true"})
    approved_only = AppConfig.from_env({ENVIRONMENT_VARIABLES["scheduler_approved"]: "true"})
    effective = AppConfig.from_env(
        {
            ENVIRONMENT_VARIABLES["scheduler_enabled"]: "true",
            ENVIRONMENT_VARIABLES["scheduler_approved"]: "true",
        }
    )

    assert requested.scheduler_enabled is False
    assert approved_only.scheduler_enabled is False
    assert effective.scheduler_enabled is True
    assert effective.read_only is True


def test_environment_can_explicitly_confirm_safe_values() -> None:
    values = {variable_name: "false" for variable_name in ENVIRONMENT_VARIABLES.values()}
    values[ENVIRONMENT_VARIABLES["environment"]] = "unit-test"
    values[ENVIRONMENT_VARIABLES["log_level"]] = "warning"
    values[ENVIRONMENT_VARIABLES["read_only"]] = "true"
    config = AppConfig.from_env(values)
    assert config.environment == "unit-test"
    assert config.log_level == "WARNING"


def test_invalid_log_level_is_rejected() -> None:
    with pytest.raises(InvalidConfiguration, match="log_level"):
        AppConfig(log_level="TRACE")
