"""Tests for AuditLog model"""

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


class TestAuditLogModel:
    """Tests for the AuditLog model"""

    def test_audit_log_creation(self, app, test_user, test_project):
        """Test creating an audit log entry"""
        with app.app_context():
            audit_log = AuditLog(
                user_id=test_user.id,
                action="created",
                entity_type="Project",
                entity_id=test_project.id,
                entity_name=test_project.name,
                change_description=f'Created project "{test_project.name}"',
            )
            db.session.add(audit_log)
            db.session.commit()

            assert audit_log.id is not None
            assert audit_log.user_id == test_user.id
            assert audit_log.action == "created"
            assert audit_log.entity_type == "Project"
            assert audit_log.entity_id == test_project.id
            assert audit_log.created_at is not None

    def test_audit_log_log_change_method(self, app, test_user, test_project):
        """Test the AuditLog.log_change() class method"""
        with app.app_context():
            AuditLog.log_change(
                user_id=test_user.id,
                action="updated",
                entity_type="Project",
                entity_id=test_project.id,
                field_name="name",
                old_value="Old Name",
                new_value="New Name",
                entity_name=test_project.name,
                change_description="Updated project name",
            )

            audit_log = AuditLog.query.filter_by(
                user_id=test_user.id, entity_type="Project", entity_id=test_project.id, field_name="name"
            ).first()

            assert audit_log is not None
            assert audit_log.action == "updated"
            assert audit_log.field_name == "name"
            assert audit_log.get_old_value() == "Old Name"
            assert audit_log.get_new_value() == "New Name"

    def test_audit_log_value_encoding(self, app, test_user, test_project):
        """Test that values are properly encoded/decoded"""
        with app.app_context():
            # Test with datetime
            old_dt = datetime(2024, 1, 1, 12, 0, 0)
            new_dt = datetime(2024, 1, 2, 12, 0, 0)

            AuditLog.log_change(
                user_id=test_user.id,
                action="updated",
                entity_type="Project",
                entity_id=test_project.id,
                field_name="updated_at",
                old_value=old_dt,
                new_value=new_dt,
                entity_name=test_project.name,
            )

            audit_log = AuditLog.query.filter_by(
                entity_type="Project", entity_id=test_project.id, field_name="updated_at"
            ).first()

            assert audit_log is not None
            # Values should be JSON-encoded strings
            assert isinstance(audit_log.old_value, str)
            assert isinstance(audit_log.new_value, str)
            # Decoded values should match
            assert audit_log.get_old_value() == old_dt.isoformat()
            assert audit_log.get_new_value() == new_dt.isoformat()

    def test_audit_log_get_for_entity(self, app, test_user, test_project):
        """Test getting audit logs for a specific entity"""
        with app.app_context():
            # Create multiple audit logs for the same entity
            for i in range(5):
                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,
                )

            # Get audit logs for this entity
            logs = AuditLog.get_for_entity("Project", test_project.id, limit=3)

            assert len(logs) == 3
            assert all(log.entity_type == "Project" for log in logs)
            assert all(log.entity_id == test_project.id for log in logs)

    def test_audit_log_get_for_user(self, app, test_user, test_project):
        """Test getting audit logs for a specific user"""
        with app.app_context():
            # Create multiple audit logs by the same user
            for i in range(5):
                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,
                )

            # Get audit logs for this user
            logs = AuditLog.get_for_user(test_user.id, limit=3)

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

    def test_audit_log_get_recent(self, app, test_user, test_project):
        """Test getting recent audit logs with filters"""
        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
            created_logs = AuditLog.get_recent(action="created", limit=10)
            assert len(created_logs) == 1
            assert created_logs[0].action == "created"

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

    def test_audit_log_to_dict(self, app, test_user, test_project):
        """Test converting audit log to dictionary"""
        with app.app_context():
            audit_log = AuditLog(
                user_id=test_user.id,
                action="created",
                entity_type="Project",
                entity_id=test_project.id,
                entity_name=test_project.name,
                change_description="Test description",
            )
            db.session.add(audit_log)
            db.session.commit()

            log_dict = audit_log.to_dict()

            assert isinstance(log_dict, dict)
            assert log_dict["id"] == audit_log.id
            assert log_dict["user_id"] == test_user.id
            assert log_dict["action"] == "created"
            assert log_dict["entity_type"] == "Project"
            assert log_dict["entity_id"] == test_project.id
            assert log_dict["username"] == test_user.username
            assert log_dict["display_name"] == test_user.display_name

    def test_audit_log_icons_and_colors(self, app, test_user, test_project):
        """Test icon and color methods"""
        with app.app_context():
            created_log = AuditLog(
                user_id=test_user.id, action="created", entity_type="Project", entity_id=test_project.id
            )
            assert "green" in created_log.get_icon()
            assert created_log.get_color() == "green"

            updated_log = AuditLog(
                user_id=test_user.id, action="updated", entity_type="Project", entity_id=test_project.id
            )
            assert "blue" in updated_log.get_icon()
            assert updated_log.get_color() == "blue"

            deleted_log = AuditLog(
                user_id=test_user.id, action="deleted", entity_type="Project", entity_id=test_project.id
            )
            assert "red" in deleted_log.get_icon()
            assert deleted_log.get_color() == "red"
