"""Tests for Authentication System (core/auth.py)."""

import pytest

from core.auth import AuthManager


@pytest.fixture
def auth_with_key(monkeypatch):
    """Create AuthManager with a known master key."""
    monkeypatch.setenv("MASTER_API_KEY", "test-master-key-12345")
    return AuthManager()


@pytest.fixture
def auth_without_key(monkeypatch):
    """Create AuthManager without env key (auto-generates)."""
    monkeypatch.delenv("MASTER_API_KEY", raising=False)
    return AuthManager()


class TestMasterKeyInit:
    """Test master key initialization."""

    def test_loads_key_from_env(self, auth_with_key):
        """Master key should be loaded from MASTER_API_KEY env var."""
        assert auth_with_key.master_api_key == "test-master-key-12345"

    def test_generates_key_when_missing(self, auth_without_key):
        """Should auto-generate a key when env var is not set."""
        assert auth_without_key.master_api_key is not None
        assert len(auth_without_key.master_api_key) > 20

    def test_generated_keys_are_unique(self, monkeypatch):
        """Each init without env should produce a different key."""
        monkeypatch.delenv("MASTER_API_KEY", raising=False)
        a = AuthManager()
        b = AuthManager()
        assert a.master_api_key != b.master_api_key


class TestMasterKeyValidation:
    """Test master key validation."""

    def test_valid_key_accepted(self, auth_with_key):
        """Correct master key should be accepted."""
        assert auth_with_key.validate_master_key("test-master-key-12345") is True

    def test_invalid_key_rejected(self, auth_with_key):
        """Wrong master key should be rejected."""
        assert auth_with_key.validate_master_key("wrong-key") is False

    def test_empty_key_rejected(self, auth_with_key):
        """Empty string should be rejected."""
        assert auth_with_key.validate_master_key("") is False

    def test_timing_safe_comparison(self, auth_with_key):
        """Validation should use timing-safe comparison (secrets.compare_digest)."""
        # This is a behavioral test: both wrong keys should take similar time
        # We mainly verify the method works correctly for various inputs
        assert auth_with_key.validate_master_key("test-master-key-12345") is True
        assert auth_with_key.validate_master_key("test-master-key-12346") is False

    def test_get_master_key(self, auth_with_key):
        """get_master_key should return the current key."""
        assert auth_with_key.get_master_key() == "test-master-key-12345"


class TestProjectKeys:
    """Test project-specific key management."""

    def test_add_project_key_custom(self, auth_with_key):
        """Should store a custom project key."""
        auth_with_key.add_project_key("proj1", "my-project-key")
        assert auth_with_key.validate_project_key("proj1", "my-project-key") is True

    def test_add_project_key_generated(self, auth_with_key):
        """Should generate a key when none provided."""
        key = auth_with_key.add_project_key("proj1")
        assert key is not None
        assert len(key) > 20
        assert auth_with_key.validate_project_key("proj1", key) is True

    def test_project_key_wrong_project(self, auth_with_key):
        """Project key should not work for a different project."""
        auth_with_key.add_project_key("proj1", "key-for-proj1")
        # proj2 has no key, so it falls back to master key
        assert auth_with_key.validate_project_key("proj2", "key-for-proj1") is False

    def test_fallback_to_master_key(self, auth_with_key):
        """Projects without a specific key should accept master key."""
        assert auth_with_key.validate_project_key("no-key-project", "test-master-key-12345") is True

    def test_remove_project_key(self, auth_with_key):
        """Removing a project key should make it fall back to master."""
        auth_with_key.add_project_key("proj1", "proj-key")
        auth_with_key.remove_project_key("proj1")
        # After removal, should fall back to master key
        assert auth_with_key.validate_project_key("proj1", "proj-key") is False
        assert auth_with_key.validate_project_key("proj1", "test-master-key-12345") is True

    def test_remove_nonexistent_key(self, auth_with_key):
        """Removing a key for a project that has none should not raise."""
        auth_with_key.remove_project_key("nonexistent")  # Should not raise

    def test_has_project_key(self, auth_with_key):
        """has_project_key should reflect current state."""
        assert auth_with_key.has_project_key("proj1") is False
        auth_with_key.add_project_key("proj1", "key")
        assert auth_with_key.has_project_key("proj1") is True
        auth_with_key.remove_project_key("proj1")
        assert auth_with_key.has_project_key("proj1") is False
