"""
Comprehensive Tests for Irene Auth - All 8 Features
Simple version without emojis for Windows console compatibility
"""

import sys
import traceback
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker

import irene_auth
from irene_auth import (
    AuthManager,
    AuthConfig,
    User,
    Role,
    RefreshToken,
    RBACManager,
    Base
)


def run_test(name, func):
    """Run a single test and report results"""
    try:
        print(f"\n[{name}]")
        func()
        print(f"  PASS")
        return True
    except Exception as e:
        print(f"  FAIL: {e}")
        traceback.print_exc()
        return False


def test_rust_crypto():
    """Test Rust cryptography primitives"""
    # Password hashing
    hash1 = irene_auth.hash_password("SecurePass123!")
    assert irene_auth.verify_password("SecurePass123!", hash1)
    
    # Token generation
    token = irene_auth.generate_token(32)
    token_hash = irene_auth.hash_token(token)
    assert irene_auth.verify_token_hash(token, token_hash)
    
    # JWT
    jwt = irene_auth.jwt_encode(
        {"sub": "test@example.com", "email": "test@example.com"},
        b"secret-key-min-32-characters-long",
        3600,
        "HS256"
    )
    claims = irene_auth.jwt_decode(
        jwt,
        b"secret-key-min-32-characters-long",
        ["HS256"]
    )
    assert "exp" in claims


def test_user_model():
    """Test Feature 1: User Model"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    engine = create_engine(config.database_url)
    Base.metadata.create_all(engine)
    Session = sessionmaker(bind=engine)
    db = Session()
    
    user = User(
        email="test@example.com",
        password_hash=irene_auth.hash_password("password"),
        is_active=True
    )
    db.add(user)
    db.commit()
    
    found = db.query(User).filter_by(email="test@example.com").first()
    assert found is not None
    assert found.email == "test@example.com"
    
    db.close()


def test_signup_login():
    """Test Feature 3: Signup + Login"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    db = auth.get_session()
    
    # Signup
    user, token = auth.signup("user@example.com", "SecurePass123!", db=db)
    assert user.email == "user@example.com"
    assert token is not None
    
    # Verify email
    auth.verification_manager.verify_email(token, db)
    db.commit()
    
    # Login
    tokens = auth.login("user@example.com", "SecurePass123!", db=db)
    assert "access_token" in tokens
    assert "refresh_token" in tokens
    
    db.close()


def test_jwt_tokens():
    """Test Feature 4: JWT Access Tokens"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    db = auth.get_session()
    
    user, _ = auth.signup("jwt@example.com", "password123", require_verification=False, db=db)
    
    # Create JWT
    jwt_token = auth.jwt_manager.create_access_token(user)
    assert jwt_token is not None
    
    # Decode JWT
    claims = auth.jwt_manager.decode_access_token(jwt_token)
    assert claims["sub"] == str(user.id)
    
    db.close()


def test_refresh_tokens():
    """Test Feature 5: Refresh Tokens"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    db = auth.get_session()
    
    user, _ = auth.signup("refresh@example.com", "password123", require_verification=False, db=db)
    
    # Create refresh token
    refresh_token = auth.refresh_manager.create_refresh_token(user, db)
    assert refresh_token is not None
    
    # Use refresh token
    new_access = auth.refresh_access_token(refresh_token, db)
    assert new_access is not None
    
    # Revoke token
    revoked = auth.refresh_manager.revoke_token(refresh_token, db)
    assert revoked == True
    
    db.close()


def test_rbac():
    """Test Feature 6: Role-Based Access Control"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    rbac = RBACManager()
    db = auth.get_session()
    
    # Create roles
    rbac.create_role("admin", "Administrator", db)
    rbac.create_role("user", "Regular User", db)
    
    # Create user
    user, _ = auth.signup("rbac@example.com", "password123", require_verification=False, db=db)
    
    # Assign roles
    rbac.assign_role(user, "user", db)
    db.refresh(user)
    
    # Check roles
    assert user.has_role("user") == True
    assert user.has_role("admin") == False
    
    db.close()


def test_password_reset():
    """Test Feature 7: Password Reset"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    db = auth.get_session()
    
    # Create user
    user, _ = auth.signup("reset@example.com", "OldPass123!", require_verification=False, db=db)
    
    # Request reset
    reset_token = auth.reset_manager.request_password_reset("reset@example.com", db)
    assert reset_token is not None
    
    # Reset password
    success = auth.reset_manager.reset_password(reset_token, "NewPass456!", db)
    assert success == True
    
    # Login with new password
    tokens = auth.login("reset@example.com", "NewPass456!", require_verified=False, db=db)
    assert tokens is not None
    
    db.close()


def test_email_verification():
    """Test Feature 8: Email Verification"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    db = auth.get_session()
    
    # Signup with verification
    user, token = auth.signup("verify@example.com", "password123", require_verification=True, db=db)
    assert user.is_verified == False
    assert token is not None
    
    # Verify email
    success = auth.verification_manager.verify_email(token, db)
    assert success == True
    
    db.refresh(user)
    assert user.is_verified == True
    
    db.close()


def test_complete_workflow():
    """Integration test: Complete workflow with all features"""
    config = AuthConfig(
        database_url="sqlite:///:memory:",
        secret_key="test-secret-key-min-32-characters-long"
    )
    auth = AuthManager(config)
    rbac = RBACManager()
    db = auth.get_session()
    
    # Create role
    rbac.create_role("user", "Regular User", db)
    
    # Signup
    user, verification_token = auth.signup("integration@example.com", "Pass123!", db=db)
    
    # Verify email
    auth.verification_manager.verify_email(verification_token, db)
    db.commit()
    
    # Assign role
    rbac.assign_role(user, "user", db)
    db.refresh(user)
    assert user.has_role("user")
    
    # Login
    tokens = auth.login("integration@example.com", "Pass123!", db=db)
    
    # Refresh access token
    new_access = auth.refresh_access_token(tokens["refresh_token"], db)
    assert new_access is not None
    
    # Password reset
    reset_token = auth.reset_manager.request_password_reset("integration@example.com", db)
    auth.reset_manager.reset_password(reset_token, "NewPass456!", db)
    
    # Login with new password
    final_tokens = auth.login("integration@example.com", "NewPass456!", db=db)
    assert final_tokens is not None
    
    db.close()


if __name__ == "__main__":
    print("="*70)
    print("IRENE AUTH - COMPREHENSIVE FEATURE TESTS")
    print("="*70)
    
    tests = [
        ("RUST CRYPTO (Features 2, 4 primitives)", test_rust_crypto),
        ("FEATURE 1: User Model", test_user_model),
        ("FEATURE 3: Signup + Login", test_signup_login),
        ("FEATURE 4: JWT Access Tokens", test_jwt_tokens),
        ("FEATURE 5: Refresh Tokens", test_refresh_tokens),
        ("FEATURE 6: RBAC", test_rbac),
        ("FEATURE 7: Password Reset", test_password_reset),
        ("FEATURE 8: Email Verification", test_email_verification),
        ("INTEGRATION: Complete Workflow", test_complete_workflow),
    ]
    
    passed = 0
    failed = 0
    
    for name, func in tests:
        if run_test(name, func):
            passed += 1
        else:
            failed += 1
    
    print("\n" + "="*70)
    print(f"RESULTS: {passed} passed, {failed} failed")
    print("="*70)
    
    if failed == 0:
        print("\nALL TESTS PASSED!")
        sys.exit(0)
    else:
        print(f"\n{failed} TEST(S) FAILED")
        sys.exit(1)
