"""Tests for authentication-related database models."""

from datetime import datetime, timezone

import pytest
from sqlalchemy import create_engine
from sqlalchemy.exc import IntegrityError
from sqlalchemy.orm import sessionmaker

from local_deep_research.database.models import Base, User


class TestUserModel:
    """Test suite for the User model."""

    @pytest.fixture
    def engine(self):
        """Create an in-memory SQLite database for testing."""
        engine = create_engine("sqlite:///:memory:")
        Base.metadata.create_all(engine)
        yield engine
        engine.dispose()

    @pytest.fixture
    def session(self, engine):
        """Create a database session for testing."""
        Session = sessionmaker(bind=engine)
        session = Session()
        yield session
        session.close()

    def test_create_user(self, session):
        """Test creating a new user."""
        user = User(username="testuser")

        session.add(user)
        session.commit()

        # Retrieve the user
        saved_user = session.query(User).filter_by(username="testuser").first()
        assert saved_user is not None
        assert saved_user.username == "testuser"
        assert saved_user.created_at is not None
        assert saved_user.database_version == 1

    def test_unique_username_constraint(self, session):
        """Test that usernames must be unique."""
        user1 = User(username="testuser")
        session.add(user1)
        session.commit()

        # Try to create another user with the same username
        user2 = User(username="testuser")
        session.add(user2)

        with pytest.raises(IntegrityError):
            session.commit()

    def test_user_timestamps(self, session):
        """Test that created_at is set correctly."""
        user = User(username="testuser")

        # Before saving, created_at should be None
        assert user.created_at is None

        session.add(user)
        session.commit()

        # After saving, created_at should be set
        assert user.created_at is not None
        assert isinstance(user.created_at, datetime)

        # Update last_login
        user.last_login = datetime.now(timezone.utc)
        session.commit()

        # Verify last_login is set
        assert user.last_login is not None
        assert user.last_login >= user.created_at

    def test_user_last_login(self, session):
        """Test last_login timestamp."""
        user = User(username="testuser")

        session.add(user)
        session.commit()

        # Initially last_login should be None
        assert user.last_login is None

        # Update last_login
        login_time = datetime.now(timezone.utc)
        user.last_login = login_time
        session.commit()

        # Verify last_login is set
        saved_user = session.query(User).filter_by(username="testuser").first()
        assert saved_user.last_login is not None
        assert abs((saved_user.last_login - login_time).total_seconds()) < 1

    def test_user_representation(self):
        """Test string representation of User model."""
        user = User(username="testuser")

        # Should have a meaningful string representation
        assert repr(user) == "<User testuser>"

    def test_database_path_property(self):
        """Test the database_path property generates consistent paths."""
        user1 = User(username="testuser")
        user2 = User(username="testuser")
        user3 = User(username="different")

        # Same username should generate same path
        assert user1.database_path == user2.database_path

        # Different username should generate different path
        assert user1.database_path != user3.database_path

        # Path should have expected format
        assert user1.database_path.startswith("ldr_user_")
        assert user1.database_path.endswith(".db")

    def test_database_version_default(self, session):
        """Test that database_version defaults to 1."""
        user = User(username="testuser")

        session.add(user)
        session.commit()

        assert user.database_version == 1

        # Can update version
        user.database_version = 2
        session.commit()

        saved_user = session.query(User).filter_by(username="testuser").first()
        assert saved_user.database_version == 2

    def test_username_with_special_characters(self, session):
        """Test usernames with special characters."""
        special_users = [
            "user@email.com",
            "user-with-dashes",
            "user_with_underscores",
            "user.with.dots",
            "user123",
            "UPPERCASE",
            "مستخدم",  # Arabic
            "用户",  # Chinese
            "🎉user",  # Emoji
        ]

        for username in special_users:
            user = User(username=username)
            session.add(user)

        session.commit()

        # All should be saved successfully
        assert session.query(User).count() == len(special_users)

        # Each should have a valid database path
        for username in special_users:
            user = session.query(User).filter_by(username=username).first()
            assert user is not None
            assert user.database_path.startswith("ldr_user_")
            assert user.database_path.endswith(".db")
            # Path should be filesystem-safe (no special chars)
            assert all(c.isalnum() or c in "_." for c in user.database_path)

    def test_user_query_operations(self, session):
        """Test various query operations on User model."""
        # Create multiple users
        users = []
        for i in range(5):
            user = User(username=f"user{i}")
            users.append(user)
            session.add(user)

        session.commit()

        # Query all users
        all_users = session.query(User).all()
        assert len(all_users) == 5

        # Query by username
        user2 = session.query(User).filter_by(username="user2").first()
        assert user2 is not None
        assert user2.username == "user2"

        # Query ordered by created_at
        ordered_users = session.query(User).order_by(User.created_at).all()
        assert len(ordered_users) == 5

        # Query with limit
        limited_users = session.query(User).limit(3).all()
        assert len(limited_users) == 3
