from typing import Any

from django.contrib.auth import get_user_model
from django.db import transaction

from apps.core.audit.models import AuditLog
from apps.core.audit.tasks import write_audit_log


def log_audit(
    *,
    actor,
    action: str,
    target_model: str = "",
    object_id: str = "",
    object_repr: str = "",
    changes: dict[str, Any] | None = None,
    target_app: str = "",
    ip_address: str | None = None,
    user_agent: str = "",
) -> None:
    """Persist an audit row after the current DB transaction commits."""
    User = get_user_model()
    actor_id = actor.pk if isinstance(actor, User) else None

    def _write():
        write_audit_log.delay(
            actor_id=actor_id,
            action=action,
            target_app=target_app[:64],
            target_model=target_model[:64],
            object_id=str(object_id)[:64] if object_id is not None else "",
            object_repr=object_repr[:200],
            changes=changes,
            ip_address=ip_address,
            user_agent=user_agent[:512],
            path="",
            method="",
        )

    transaction.on_commit(_write)


class AuditableMixin:
    """Optional mixin for CBVs that call log_audit from dispatch or form_valid."""

    audit_action = AuditLog.Action.UPDATE

    def get_audit_object_repr(self):
        return str(getattr(self, "object", ""))[:200]
