"""Tests for configuration module."""

import os
import tempfile
from pathlib import Path

import yaml

from iq_sdk.config import (
    Settings,
    SiteConfig,
    _parse_sites_from_env,
    generate_env_template,
    load_settings,
)


class TestSiteConfig:
    """Test SiteConfig class."""

    def test_defaults(self) -> None:
        """Test default site config."""
        config = SiteConfig()

        assert config.id == "default"
        assert config.host == "http://localhost:3000"
        assert config.env == {}  # Empty dict for custom env vars
        assert config.api_key == ""
        assert config.api_secret == ""

    def test_custom_site(self) -> None:
        """Test custom site configuration."""
        config = SiteConfig(
            id="production",
            host="http://prod:3000",
            api_key="prod-worker",
            env={"API_KEY": "test-key"},
        )

        assert config.id == "production"
        assert config.host == "http://prod:3000"
        assert config.env == {"API_KEY": "test-key"}
        assert config.api_key == "prod-worker"

    def test_load_api_secret_from_env(self) -> None:
        """Test API secret loading from environment."""
        config = SiteConfig(id="test-site")

        os.environ["IQ_SITE_TEST_SITE_API_SECRET"] = "secret123"
        try:
            secret = config.load_api_secret()
            assert secret == "secret123"
        finally:
            del os.environ["IQ_SITE_TEST_SITE_API_SECRET"]

    def test_load_api_secret_from_file(self) -> None:
        """Test API secret loading from file reference."""
        config = SiteConfig(id="file-site")

        with tempfile.NamedTemporaryFile(mode="w", delete=False) as f:
            f.write("file-secret")
            f.flush()

            os.environ["IQ_SITE_FILE_SITE_API_SECRET_FILE"] = f.name
            try:
                secret = config.load_api_secret()
                assert secret == "file-secret"
            finally:
                del os.environ["IQ_SITE_FILE_SITE_API_SECRET_FILE"]
                Path(f.name).unlink()

    def test_load_api_secret_from_json_file_with_key(self) -> None:
        """Test API secret extraction from JSON file with _API_SECRET_KEY."""
        import json

        config = SiteConfig(id="json-site")

        secret_data = {
            "credentials": {
                "api_secret": "json-nested-secret",
                "api_key": "key123",
            },
            "other": "data",
        }

        with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".json") as f:
            json.dump(secret_data, f)
            f.flush()

            os.environ["IQ_SITE_JSON_SITE_API_SECRET_FILE"] = f.name
            os.environ["IQ_SITE_JSON_SITE_API_SECRET_KEY"] = "credentials.api_secret"
            try:
                secret = config.load_api_secret()
                assert secret == "json-nested-secret"
            finally:
                del os.environ["IQ_SITE_JSON_SITE_API_SECRET_FILE"]
                del os.environ["IQ_SITE_JSON_SITE_API_SECRET_KEY"]
                Path(f.name).unlink()

    def test_load_api_secret_from_yaml_file_with_key(self) -> None:
        """Test API secret extraction from YAML file with _API_SECRET_KEY."""
        import yaml

        config = SiteConfig(id="yaml-site")

        secret_data = {
            "services": {
                "worker": {
                    "auth": {
                        "api_secret": "yaml-deep-secret",
                    }
                }
            }
        }

        with tempfile.NamedTemporaryFile(mode="w", delete=False, suffix=".yaml") as f:
            yaml.dump(secret_data, f)
            f.flush()

            os.environ["IQ_SITE_YAML_SITE_API_SECRET_FILE"] = f.name
            os.environ["IQ_SITE_YAML_SITE_API_SECRET_KEY"] = "services.worker.auth.api_secret"
            try:
                secret = config.load_api_secret()
                assert secret == "yaml-deep-secret"
            finally:
                del os.environ["IQ_SITE_YAML_SITE_API_SECRET_FILE"]
                del os.environ["IQ_SITE_YAML_SITE_API_SECRET_KEY"]
                Path(f.name).unlink()

    def test_get_auth(self) -> None:
        """Test auth credentials retrieval."""
        config = SiteConfig(id="auth-site", api_key="testkey")

        os.environ["IQ_SITE_AUTH_SITE_API_SECRET"] = "testsecret"
        try:
            auth = config.get_auth()
            assert auth["api_key"] == "testkey"
            assert auth["api_secret"] == "testsecret"
        finally:
            del os.environ["IQ_SITE_AUTH_SITE_API_SECRET"]

    def test_env_override_host(self) -> None:
        """Test host override via ENV."""
        config = SiteConfig(id="override", host="http://original:3000")

        os.environ["IQ_SITE_OVERRIDE_HOST"] = "http://new:4000"
        try:
            assert config.get_host() == "http://new:4000"
        finally:
            del os.environ["IQ_SITE_OVERRIDE_HOST"]


class TestSettings:
    """Test Settings class."""

    def test_default_settings(self) -> None:
        """Test default settings values."""
        settings = Settings()

        assert settings.project_name == "my-project"
        assert settings.site.id == "default"
        assert settings.sites == []
        assert settings.worker.threads == 1

    def test_get_site(self) -> None:
        """Test getting site by ID."""
        settings = Settings(
            site=SiteConfig(id="default"),
            sites=[
                SiteConfig(id="production"),
                SiteConfig(id="staging"),
            ],
        )

        assert settings.get_site("default") == settings.site
        assert settings.get_site("production").id == "production"
        assert settings.get_site("staging").id == "staging"
        assert settings.get_site("nonexistent") is None

    def test_get_sites(self) -> None:
        """Test getting multiple sites."""
        settings = Settings(
            site=SiteConfig(id="default"),
            sites=[
                SiteConfig(id="production"),
                SiteConfig(id="staging"),
            ],
        )

        all_sites = settings.get_sites()
        assert len(all_sites) == 3

        selected = settings.get_sites(["production", "staging"])
        assert len(selected) == 2
        assert all(s.id in ["production", "staging"] for s in selected)

    def test_list_site_ids(self) -> None:
        """Test listing all site IDs."""
        settings = Settings(
            site=SiteConfig(id="default"),
            sites=[
                SiteConfig(id="production"),
                SiteConfig(id="staging"),
            ],
        )

        ids = settings.list_site_ids()
        assert ids == ["default", "production", "staging"]


class TestLoadSettings:
    """Test load_settings function."""

    def test_load_from_yaml(self) -> None:
        """Test loading settings from YAML file."""
        config = {
            "project_name": "yaml-project",
            "site": {
                "id": "default",
                "host": "http://yaml-host:3000",
            },
            "sites": [
                {"id": "prod", "host": "http://prod:3000"},
            ],
            "worker": {"threads": 8},
        }

        with tempfile.NamedTemporaryFile(
            mode="w", suffix=".yml", delete=False
        ) as f:
            yaml.dump(config, f)
            f.flush()

            settings = load_settings(f.name)

            assert settings.project_name == "yaml-project"
            assert settings.site.host == "http://yaml-host:3000"
            assert len(settings.sites) == 1
            assert settings.sites[0].id == "prod"
            assert settings.worker.threads == 8

        Path(f.name).unlink()

    def test_load_with_overrides(self) -> None:
        """Test loading with override values."""
        settings = load_settings(
            overrides={"worker": {"threads": 32}}
        )

        assert settings.worker.threads == 32


class TestParseSitesFromEnv:
    """Test parsing sites from environment variables."""

    def test_id_based_sites(self) -> None:
        """Test parsing ID-based site variables."""
        os.environ["IQ_SITE_PRODUCTION_ACTIVE"] = "1"
        os.environ["IQ_SITE_PRODUCTION_HOST"] = "http://prod:3000"
        os.environ["IQ_SITE_PRODUCTION_API_KEY"] = "prod-worker"
        os.environ["IQ_SITE_STAGING_ACTIVE"] = "1"
        os.environ["IQ_SITE_STAGING_HOST"] = "http://stage:3000"

        try:
            sites = _parse_sites_from_env()
            assert len(sites) == 2

            # Sites are returned in arbitrary order (dict iteration)
            site_ids = {s.id for s in sites}
            assert "production" in site_ids
            assert "staging" in site_ids

            prod_site = next(s for s in sites if s.id == "production")
            assert prod_site.host == "http://prod:3000"
            assert prod_site.api_key == "prod-worker"
            assert prod_site.is_active()
        finally:
            del os.environ["IQ_SITE_PRODUCTION_ACTIVE"]
            del os.environ["IQ_SITE_PRODUCTION_HOST"]
            del os.environ["IQ_SITE_PRODUCTION_API_KEY"]
            del os.environ["IQ_SITE_STAGING_ACTIVE"]
            del os.environ["IQ_SITE_STAGING_HOST"]

    def test_inactive_sites_not_parsed(self) -> None:
        """Test that sites without _ACTIVE=1 are not parsed from ENV."""
        os.environ["IQ_SITE_MYSITE_HOST"] = "http://mysite:3000"
        # Note: _ACTIVE not set, so site should not be created

        try:
            sites = _parse_sites_from_env()
            assert len(sites) == 0
        finally:
            del os.environ["IQ_SITE_MYSITE_HOST"]


class TestSiteActive:
    """Test site active/inactive logic."""

    def test_site_active_default(self) -> None:
        """Test site is active by default."""
        config = SiteConfig(id="test")
        assert config.active is True
        assert config.is_active() is True

    def test_site_inactive_config(self) -> None:
        """Test site can be set inactive in config."""
        config = SiteConfig(id="test", active=False)
        assert config.active is False
        assert config.is_active() is False

    def test_site_deactivate_via_env(self) -> None:
        """Test site can be deactivated via ENV."""
        config = SiteConfig(id="test-site", active=True)

        os.environ["IQ_SITE_TEST_SITE_ACTIVE"] = "0"
        try:
            assert config.is_active() is False
        finally:
            del os.environ["IQ_SITE_TEST_SITE_ACTIVE"]

    def test_site_activate_via_env(self) -> None:
        """Test site can be activated via ENV."""
        config = SiteConfig(id="test-site", active=False)

        os.environ["IQ_SITE_TEST_SITE_ACTIVE"] = "1"
        try:
            assert config.is_active() is True
        finally:
            del os.environ["IQ_SITE_TEST_SITE_ACTIVE"]


class TestGenerateEnvTemplate:
    """Test .env template generation."""

    def test_generate_template(self) -> None:
        """Test generating .env template."""
        settings = Settings(
            site=SiteConfig(id="default", api_key="default-key"),
            sites=[
                SiteConfig(id="production", api_key="prod-key"),
            ],
        )

        template = generate_env_template(settings)

        assert "IQ_SITE_DEFAULT_API_SECRET=" in template
        assert "IQ_SITE_PRODUCTION_API_SECRET=" in template
        assert "IQ_SITE_DEFAULT_API_KEY=default-key" in template
        assert "IQ_SITE_PRODUCTION_API_KEY=prod-key" in template
