"""
Unit tests for app/core/auth_tokens.py.
"""

import pytest

from app.core.auth_tokens import (
    create_access_token,
    create_refresh_token,
    decode_token,
    hash_password,
    verify_password,
)
from app.core.exceptions import AuthenticationError


class TestPasswordHashing:
    def test_correct_password_verifies(self):
        hashed = hash_password("correct-password-1")
        assert verify_password("correct-password-1", hashed) is True

    def test_wrong_password_fails(self):
        hashed = hash_password("correct-password-1")
        assert verify_password("wrong-password-1", hashed) is False

    def test_hash_is_not_plaintext(self):
        hashed = hash_password("correct-password-1")
        assert hashed != "correct-password-1"

    def test_same_password_produces_different_hashes(self):
        """bcrypt salts each hash — two hashes of the same password must differ."""
        hash1 = hash_password("same-password-1")
        hash2 = hash_password("same-password-1")
        assert hash1 != hash2
        # but both still verify correctly
        assert verify_password("same-password-1", hash1)
        assert verify_password("same-password-1", hash2)


class TestJWTTokens:
    def test_access_token_round_trip(self):
        token = create_access_token("user-abc", "test@example.com")
        payload = decode_token(token, expected_type="access")
        assert payload["sub"] == "user-abc"
        assert payload["email"] == "test@example.com"

    def test_refresh_token_round_trip(self):
        token = create_refresh_token("user-abc")
        payload = decode_token(token, expected_type="refresh")
        assert payload["sub"] == "user-abc"

    def test_refresh_token_used_as_access_token_raises(self):
        token = create_refresh_token("user-abc")
        with pytest.raises(AuthenticationError):
            decode_token(token, expected_type="access")

    def test_access_token_used_as_refresh_token_raises(self):
        token = create_access_token("user-abc", "test@example.com")
        with pytest.raises(AuthenticationError):
            decode_token(token, expected_type="refresh")

    def test_tampered_token_raises(self):
        token = create_access_token("user-abc", "test@example.com")
        with pytest.raises(AuthenticationError):
            decode_token(token + "tampered", expected_type="access")

    def test_garbage_token_raises(self):
        with pytest.raises(AuthenticationError):
            decode_token("not-a-real-jwt-at-all", expected_type="access")
