"""Tests for app.core.sso — SSO/OIDC config and utilities"""

import pytest
from unittest.mock import AsyncMock, MagicMock, patch


class TestOIDCConfig:
    def test_defaults(self):
        from app.core.sso import OIDCConfig
        cfg = OIDCConfig()
        assert cfg.issuer == ""
        assert cfg.client_id == ""
        assert cfg.scopes == "openid profile email"

    def test_from_tenant_config_full(self):
        from app.core.sso import OIDCConfig
        config = {
            "oidc_issuer": "https://accounts.example.com",
            "oidc_client_id": "client-123",
            "oidc_client_secret_encrypted": "secret-enc",
            "oidc_scopes": "openid profile",
        }
        cfg = OIDCConfig.from_tenant_config(config)
        assert cfg.issuer == "https://accounts.example.com"
        assert cfg.client_id == "client-123"
        assert cfg.client_secret == "secret-enc"
        assert cfg.authorization_endpoint == "https://accounts.example.com/authorize"
        assert cfg.token_endpoint == "https://accounts.example.com/token"
        assert cfg.userinfo_endpoint == "https://accounts.example.com/userinfo"
        assert cfg.jwks_uri == "https://accounts.example.com/.well-known/jwks.json"
        assert cfg.scopes == "openid profile"

    def test_from_tenant_config_empty(self):
        from app.core.sso import OIDCConfig
        cfg = OIDCConfig.from_tenant_config({})
        assert cfg.issuer == ""
        assert cfg.client_id == ""
        assert cfg.authorization_endpoint == "/authorize"


class TestSAMLConfig:
    def test_defaults(self):
        from app.core.sso import SAMLConfig
        cfg = SAMLConfig()
        assert cfg.idp_entity_id == ""
        assert cfg.idp_sso_url == ""

    def test_from_tenant_config(self):
        from app.core.sso import SAMLConfig
        config = {
            "saml_idp_entity_id": "https://idp.example.com/metadata",
            "saml_idp_sso_url": "https://idp.example.com/sso",
            "saml_idp_certificate": "MIID...",
            "saml_sp_entity_id": "https://sp.example.com/metadata",
        }
        cfg = SAMLConfig.from_tenant_config(config)
        assert cfg.idp_entity_id == "https://idp.example.com/metadata"
        assert cfg.idp_sso_url == "https://idp.example.com/sso"
        assert cfg.idp_certificate == "MIID..."
        assert cfg.sp_entity_id == "https://sp.example.com/metadata"

    def test_from_tenant_config_empty(self):
        from app.core.sso import SAMLConfig
        cfg = SAMLConfig.from_tenant_config({})
        assert cfg.idp_entity_id == ""


class TestUtilityFunctions:
    def test_generate_state(self):
        from app.core.sso import generate_state
        state = generate_state()
        assert isinstance(state, str)
        assert len(state) > 20

    def test_generate_nonce(self):
        from app.core.sso import generate_nonce
        nonce = generate_nonce()
        assert isinstance(nonce, str)
        assert len(nonce) > 20

    def test_generate_state_unique(self):
        from app.core.sso import generate_state
        assert generate_state() != generate_state()


@pytest.mark.asyncio
async def test_discover_oidc_no_tenant():
    from app.core.sso import discover_oidc

    mock_scalar = MagicMock()
    mock_scalar.scalar.return_value = None

    mock_session = AsyncMock()
    mock_session.execute.return_value = mock_scalar

    mock_cm = AsyncMock()
    mock_cm.__aenter__.return_value = mock_session

    with patch("app.core.sso.async_session", return_value=mock_cm):
        result = await discover_oidc("no-such-tenant")
    assert result is None


@pytest.mark.asyncio
async def test_discover_oidc_sso_disabled():
    from app.core.sso import discover_oidc

    mock_tenant = MagicMock()
    mock_tenant.settings = {"sso": {"is_enabled": False}}

    mock_scalar_result = MagicMock()
    mock_scalar_result.scalar.return_value = mock_tenant

    mock_session = AsyncMock()
    mock_session.execute.return_value = mock_scalar_result

    mock_cm = AsyncMock()
    mock_cm.__aenter__.return_value = mock_session

    with patch("app.core.sso.async_session", return_value=mock_cm):
        result = await discover_oidc("test-tenant")
    assert result is None


@pytest.mark.asyncio
async def test_discover_oidc_oidc_enabled():
    from app.core.sso import discover_oidc

    mock_tenant = MagicMock()
    mock_tenant.settings = {
        "sso": {
            "is_enabled": True,
            "provider": "oidc",
            "oidc_issuer": "https://accounts.example.com",
            "oidc_client_id": "client-123",
        }
    }

    mock_scalar_result = MagicMock()
    mock_scalar_result.scalar.return_value = mock_tenant

    mock_session = AsyncMock()
    mock_session.execute.return_value = mock_scalar_result

    mock_cm = AsyncMock()
    mock_cm.__aenter__.return_value = mock_session

    with patch("app.core.sso.async_session", return_value=mock_cm):
        result = await discover_oidc("test-tenant")
    assert result is not None
    assert result.issuer == "https://accounts.example.com"
    assert result.client_id == "client-123"


@pytest.mark.asyncio
async def test_discover_oidc_saml_no_impl():
    from app.core.sso import discover_oidc

    mock_tenant = MagicMock()
    mock_tenant.settings = {
        "sso": {
            "is_enabled": True,
            "provider": "saml",
        }
    }

    mock_scalar_result = MagicMock()
    mock_scalar_result.scalar.return_value = mock_tenant

    mock_session = AsyncMock()
    mock_session.execute.return_value = mock_scalar_result

    mock_cm = AsyncMock()
    mock_cm.__aenter__.return_value = mock_session

    with patch("app.core.sso.async_session", return_value=mock_cm):
        result = await discover_oidc("test-tenant")
    assert result is None  # SAML not implemented yet
