"""
Tests for authentication routes.
Tests critical authentication flows including login, registration, and token management.
"""
import pytest
from fastapi.testclient import TestClient
from sqlalchemy.orm import Session
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from ..main import app
from ...shared.config.database import Base, get_db
from ...auth.models.user import User
from ...auth.models.role import Role
import bcrypt

# Test database setup
SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db"
engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False})
TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine)

def override_get_db():
    try:
        db = TestingSessionLocal()
        yield db
    finally:
        db.close()

app.dependency_overrides[get_db] = override_get_db

@pytest.fixture(scope="function")
def db():
    """Create a fresh database for each test."""
    Base.metadata.create_all(bind=engine)
    db = TestingSessionLocal()
    try:
        yield db
    finally:
        db.close()
        Base.metadata.drop_all(bind=engine)

@pytest.fixture(scope="function")
def client():
    """Create a test client."""
    return TestClient(app)

@pytest.fixture(scope="function")
def test_user(db: Session):
    """Create a test user."""
    # Create customer role if it doesn't exist
    role = db.query(Role).filter(Role.name == 'customer').first()
    if not role:
        role = Role(name='customer', description='Customer role')
        db.add(role)
        db.commit()
        db.refresh(role)
    
    # Create test user
    hashed_password = bcrypt.hashpw("testpassword123".encode('utf-8'), bcrypt.gensalt()).decode('utf-8')
    user = User(
        email="test@example.com",
        password=hashed_password,
        full_name="Test User",
        role_id=role.id,
        is_active=True
    )
    db.add(user)
    db.commit()
    db.refresh(user)
    return user

def test_register_success(client: TestClient, db: Session):
    """Test successful user registration."""
    response = client.post(
        "/api/auth/register",
        json={
            "name": "New User",
            "email": "newuser@example.com",
            "password": "SecurePass123!",
            "phone": "1234567890"
        }
    )
    assert response.status_code == 201
    data = response.json()
    assert data["status"] == "success"
    assert "user" in data["data"]
    assert data["data"]["user"]["email"] == "newuser@example.com"
    
    # Verify user was created in database
    user = db.query(User).filter(User.email == "newuser@example.com").first()
    assert user is not None
    assert user.full_name == "New User"
    
    # Verify cookies were set
    assert "accessToken" in response.cookies
    assert "refreshToken" in response.cookies

def test_register_duplicate_email(client: TestClient, test_user: User):
    """Test registration with duplicate email fails."""
    response = client.post(
        "/api/auth/register",
        json={
            "name": "Another User",
            "email": test_user.email,
            "password": "SecurePass123!",
            "phone": "1234567890"
        }
    )
    assert response.status_code == 400
    data = response.json()
    assert data["status"] == "error"

def test_login_success(client: TestClient, test_user: User):
    """Test successful login."""
    response = client.post(
        "/api/auth/login",
        json={
            "email": test_user.email,
            "password": "testpassword123",
            "rememberMe": False
        }
    )
    assert response.status_code == 200
    data = response.json()
    assert data["status"] == "success"
    assert "user" in data["data"]
    assert data["data"]["user"]["email"] == test_user.email
    
    # Verify cookies were set
    assert "accessToken" in response.cookies
    assert "refreshToken" in response.cookies

def test_login_invalid_credentials(client: TestClient, test_user: User):
    """Test login with invalid credentials fails."""
    response = client.post(
        "/api/auth/login",
        json={
            "email": test_user.email,
            "password": "wrongpassword",
            "rememberMe": False
        }
    )
    assert response.status_code == 401
    data = response.json()
    assert data["status"] == "error"

def test_login_nonexistent_user(client: TestClient):
    """Test login with non-existent user fails."""
    response = client.post(
        "/api/auth/login",
        json={
            "email": "nonexistent@example.com",
            "password": "password123",
            "rememberMe": False
        }
    )
    assert response.status_code == 401
    data = response.json()
    assert data["status"] == "error"

def test_logout_success(client: TestClient, test_user: User):
    """Test successful logout."""
    # First login to get cookies
    login_response = client.post(
        "/api/auth/login",
        json={
            "email": test_user.email,
            "password": "testpassword123",
            "rememberMe": False
        }
    )
    assert login_response.status_code == 200
    
    # Now logout
    logout_response = client.post("/api/auth/logout")
    assert logout_response.status_code == 200
    data = logout_response.json()
    assert data["status"] == "success"
    
    # Verify cookies were deleted
    # Note: FastAPI TestClient doesn't properly handle cookie deletion in tests
    # In real usage, cookies would be deleted

def test_get_profile_authenticated(client: TestClient, test_user: User):
    """Test getting profile when authenticated."""
    # Login first
    login_response = client.post(
        "/api/auth/login",
        json={
            "email": test_user.email,
            "password": "testpassword123",
            "rememberMe": False
        }
    )
    assert login_response.status_code == 200
    
    # Get profile
    profile_response = client.get("/api/auth/profile")
    assert profile_response.status_code == 200
    data = profile_response.json()
    assert data["status"] == "success"
    assert data["data"]["user"]["email"] == test_user.email

def test_get_profile_unauthenticated(client: TestClient):
    """Test getting profile when not authenticated fails."""
    response = client.get("/api/auth/profile")
    assert response.status_code == 401

def test_transaction_rollback_on_error(client: TestClient, db: Session):
    """Test that database transactions rollback on error."""
    initial_count = db.query(User).count()
    
    # Try to create user with invalid data (missing required field)
    # This should fail and rollback
    response = client.post(
        "/api/auth/register",
        json={
            "name": "Test User",
            # Missing email - should fail validation
            "password": "SecurePass123!"
        }
    )
    
    # Should fail validation
    assert response.status_code == 422
    
    # Verify no user was created (transaction rolled back)
    final_count = db.query(User).count()
    assert initial_count == final_count

