from __future__ import annotations

from pathlib import Path

import pytest
from pydantic import SecretStr, ValidationError

from configs.extra.knowledge_fs_config import KnowledgeFSConfig

_REPOSITORY_ROOT = Path(__file__).resolve().parents[4]
_KNOWLEDGE_FS_DOCKER_VARIABLES = (
    "KNOWLEDGE_FS_ENABLED",
    "KNOWLEDGE_FS_BASE_URL",
    "KNOWLEDGE_FS_JWT_SECRET",
    "KNOWLEDGE_FS_SSE_READ_TIMEOUT_SECONDS",
    "KNOWLEDGE_FS_TIMEOUT_SECONDS",
)


def test_knowledge_fs_config_normalizes_complete_connection() -> None:
    config = KnowledgeFSConfig(
        KNOWLEDGE_FS_ENABLED=True,
        KNOWLEDGE_FS_BASE_URL="  https://knowledge-fs.test/  ",
        KNOWLEDGE_FS_JWT_SECRET="  production-secret-with-at-least-32-bytes  ",
    )

    assert config.KNOWLEDGE_FS_BASE_URL == "https://knowledge-fs.test"
    assert isinstance(config.KNOWLEDGE_FS_JWT_SECRET, SecretStr)
    assert config.KNOWLEDGE_FS_JWT_SECRET.get_secret_value() == "production-secret-with-at-least-32-bytes"
    assert "production-secret" not in repr(config)
    assert "production-secret" not in config.model_dump_json()
    assert config.KNOWLEDGE_FS_SSE_READ_TIMEOUT_SECONDS == 300.0


def test_knowledge_fs_config_treats_blank_connection_as_disabled() -> None:
    config = KnowledgeFSConfig(
        KNOWLEDGE_FS_BASE_URL=" ",
        KNOWLEDGE_FS_JWT_SECRET="",
    )

    assert config.KNOWLEDGE_FS_BASE_URL is None
    assert config.KNOWLEDGE_FS_JWT_SECRET is None
    assert config.KNOWLEDGE_FS_ENABLED is False


def test_knowledge_fs_config_requires_connection_when_enabled() -> None:
    with pytest.raises(ValidationError, match="connection settings are required"):
        KnowledgeFSConfig(KNOWLEDGE_FS_ENABLED=True)


@pytest.mark.parametrize(
    ("base_url", "jwt_secret"),
    [
        ("https://knowledge-fs.test", None),
        (None, "production-secret-with-at-least-32-bytes"),
    ],
)
def test_disabled_knowledge_fs_config_allows_partial_connection(base_url: str | None, jwt_secret: str | None) -> None:
    config = KnowledgeFSConfig(
        KNOWLEDGE_FS_ENABLED=False,
        KNOWLEDGE_FS_BASE_URL=base_url,
        KNOWLEDGE_FS_JWT_SECRET=jwt_secret,
    )

    assert config.KNOWLEDGE_FS_ENABLED is False


def test_knowledge_fs_docker_config_is_not_shadowed_by_root_env() -> None:
    root_env_example = (_REPOSITORY_ROOT / "docker/.env.example").read_text(encoding="utf-8")
    api_env_example = (_REPOSITORY_ROOT / "docker/envs/core-services/api.env.example").read_text(encoding="utf-8")

    for variable in _KNOWLEDGE_FS_DOCKER_VARIABLES:
        assert f"{variable}=" not in root_env_example
        assert f"{variable}=" in api_env_example


@pytest.mark.parametrize(
    ("base_url", "jwt_secret"),
    [
        ("https://knowledge-fs.test", None),
        (None, "production-secret-with-at-least-32-bytes"),
    ],
)
def test_knowledge_fs_config_rejects_partial_connection(base_url: str | None, jwt_secret: str | None) -> None:
    with pytest.raises(ValidationError, match="must be configured together"):
        KnowledgeFSConfig(
            KNOWLEDGE_FS_ENABLED=True,
            KNOWLEDGE_FS_BASE_URL=base_url,
            KNOWLEDGE_FS_JWT_SECRET=jwt_secret,
        )


@pytest.mark.parametrize("base_url", ["knowledge-fs.test", "ftp://knowledge-fs.test", "http:///missing-host"])
def test_knowledge_fs_config_rejects_non_http_absolute_urls(base_url: str) -> None:
    with pytest.raises(ValidationError, match="absolute HTTP\\(S\\) URL"):
        KnowledgeFSConfig(
            KNOWLEDGE_FS_BASE_URL=base_url,
            KNOWLEDGE_FS_JWT_SECRET="production-secret-with-at-least-32-bytes",
        )


@pytest.mark.parametrize(
    "base_url",
    [
        "https://knowledge-fs.test:notaport",
        "https://knowledge-fs.test:65536",
    ],
)
def test_knowledge_fs_config_rejects_invalid_ports(base_url: str) -> None:
    with pytest.raises(ValidationError, match="valid port"):
        KnowledgeFSConfig(
            KNOWLEDGE_FS_BASE_URL=base_url,
            KNOWLEDGE_FS_JWT_SECRET="production-secret-with-at-least-32-bytes",
        )


@pytest.mark.parametrize(
    "base_url",
    [
        "https://user:password@knowledge-fs.test",
        "https://knowledge-fs.test?region=us",
        "https://knowledge-fs.test#gateway",
    ],
)
def test_knowledge_fs_config_rejects_unsafe_base_url_components(base_url: str) -> None:
    with pytest.raises(ValidationError, match="must not include credentials, query, or fragment"):
        KnowledgeFSConfig(
            KNOWLEDGE_FS_BASE_URL=base_url,
            KNOWLEDGE_FS_JWT_SECRET="production-secret-with-at-least-32-bytes",
        )


@pytest.mark.parametrize("timeout_seconds", [float("inf"), float("nan"), 60.0001])
def test_knowledge_fs_config_rejects_unbounded_timeouts(timeout_seconds: float) -> None:
    with pytest.raises(ValidationError):
        KnowledgeFSConfig(KNOWLEDGE_FS_TIMEOUT_SECONDS=timeout_seconds)


@pytest.mark.parametrize("timeout_seconds", [float("inf"), float("nan"), 3600.0001])
def test_knowledge_fs_config_rejects_unbounded_sse_read_timeouts(timeout_seconds: float) -> None:
    with pytest.raises(ValidationError):
        KnowledgeFSConfig(KNOWLEDGE_FS_SSE_READ_TIMEOUT_SECONDS=timeout_seconds)
