"""Smoke tests for audit trail feature"""

import pytest
from datetime import datetime
from app.models import AuditLog, Project, User, Task
from app import db


@pytest.mark.smoke
class TestAuditTrailSmoke:
    """Smoke tests to verify audit trail feature works end-to-end"""

    def test_audit_log_creation_smoke(self, app, test_user, test_project):
        """Smoke test: Create an audit log entry"""
        with app.app_context():
            audit_log = AuditLog.log_change(
                user_id=test_user.id,
                action="created",
                entity_type="Project",
                entity_id=test_project.id,
                entity_name=test_project.name,
                change_description="Smoke test audit log",
            )

            # Verify log was created (filter by user so we get the one we created, not fixture-created logs)
            logs = AuditLog.query.filter_by(
                entity_type="Project", entity_id=test_project.id, user_id=test_user.id, action="created"
            ).all()

            assert len(logs) >= 1
            assert logs[0].action == "created"
            assert logs[0].user_id == test_user.id

    def test_audit_log_field_change_tracking_smoke(self, app, test_user, test_project):
        """Smoke test: Track field-level changes"""
        with app.app_context():
            # Log a field change
            AuditLog.log_change(
                user_id=test_user.id,
                action="updated",
                entity_type="Project",
                entity_id=test_project.id,
                field_name="name",
                old_value="Old Project Name",
                new_value="New Project Name",
                entity_name=test_project.name,
            )

            # Verify field change was logged
            logs = AuditLog.query.filter_by(entity_type="Project", entity_id=test_project.id, field_name="name").all()

            assert len(logs) > 0
            log = logs[0]
            assert log.field_name == "name"
            assert log.get_old_value() == "Old Project Name"
            assert log.get_new_value() == "New Project Name"

    def test_audit_log_entity_history_smoke(self, app, test_user, test_project):
        """Smoke test: Retrieve entity history"""
        with app.app_context():
            # Create multiple audit logs for the same entity
            for i in range(3):
                AuditLog.log_change(
                    user_id=test_user.id,
                    action="updated",
                    entity_type="Project",
                    entity_id=test_project.id,
                    field_name=f"field_{i}",
                    old_value=f"old_{i}",
                    new_value=f"new_{i}",
                    entity_name=test_project.name,
                )

            # Retrieve entity history (may include fixture-created log; we expect at least our 3 updates)
            history = AuditLog.get_for_entity("Project", test_project.id, limit=10)

            assert len(history) >= 3
            assert all(log.entity_type == "Project" for log in history)
            assert all(log.entity_id == test_project.id for log in history)
            updated_logs = [log for log in history if log.action == "updated"]
            assert len(updated_logs) == 3

    def test_audit_log_user_activity_smoke(self, app, test_user, test_project):
        """Smoke test: Retrieve user activity history"""
        with app.app_context():
            # Create multiple audit logs by the same user
            for i in range(3):
                AuditLog.log_change(
                    user_id=test_user.id,
                    action="updated",
                    entity_type="Project",
                    entity_id=test_project.id,
                    field_name=f"field_{i}",
                    old_value=f"old_{i}",
                    new_value=f"new_{i}",
                    entity_name=test_project.name,
                )

            # Retrieve user activity
            user_logs = AuditLog.get_for_user(test_user.id, limit=10)

            assert len(user_logs) >= 3
            assert all(log.user_id == test_user.id for log in user_logs)

    def test_audit_log_filtering_smoke(self, app, test_user, test_project):
        """Smoke test: Filter audit logs by various criteria"""
        with app.app_context():
            # Create audit logs with different actions
            AuditLog.log_change(
                user_id=test_user.id,
                action="created",
                entity_type="Project",
                entity_id=test_project.id,
                entity_name=test_project.name,
            )
            AuditLog.log_change(
                user_id=test_user.id,
                action="updated",
                entity_type="Project",
                entity_id=test_project.id,
                field_name="name",
                old_value="Old",
                new_value="New",
                entity_name=test_project.name,
            )
            AuditLog.log_change(
                user_id=test_user.id,
                action="deleted",
                entity_type="Project",
                entity_id=test_project.id,
                entity_name=test_project.name,
            )

            # Filter by action and user so we only count the test's created log, not fixture-created logs
            created_logs = AuditLog.get_recent(action="created", user_id=test_user.id, limit=10)
            assert len(created_logs) >= 1
            assert created_logs[0].action == "created"
            # Our created log is for this project
            our_created = [log for log in created_logs if log.entity_type == "Project" and log.entity_id == test_project.id]
            assert len(our_created) == 1

            # Filter by entity type
            project_logs = AuditLog.get_recent(entity_type="Project", limit=10)
            assert len(project_logs) >= 3

            # Filter by user
            user_logs = AuditLog.get_recent(user_id=test_user.id, limit=10)
            assert len(user_logs) >= 3

    def test_audit_log_value_serialization_smoke(self, app, test_user, test_project):
        """Smoke test: Verify value serialization works correctly"""
        with app.app_context():
            # Test with various value types
            test_cases = [
                ("string", "Old Value", "New Value"),
                ("number", 123, 456),
                ("boolean", True, False),
                ("datetime", datetime(2024, 1, 1), datetime(2024, 1, 2)),
            ]

            for field_type, old_val, new_val in test_cases:
                AuditLog.log_change(
                    user_id=test_user.id,
                    action="updated",
                    entity_type="Project",
                    entity_id=test_project.id,
                    field_name=f"test_{field_type}",
                    old_value=old_val,
                    new_value=new_val,
                    entity_name=test_project.name,
                )

            # Verify all logs were created
            logs = AuditLog.query.filter_by(entity_type="Project", entity_id=test_project.id).all()

            assert len(logs) >= len(test_cases)

            # Verify values can be retrieved
            for log in logs:
                if log.field_name and log.field_name.startswith("test_"):
                    old_val = log.get_old_value()
                    new_val = log.get_new_value()
                    assert old_val is not None or log.old_value is None
                    assert new_val is not None or log.new_value is None
