from collections.abc import Callable
from typing import Any, Self
import types
import uuid

from django.contrib.auth.models import AbstractBaseUser
from django.db.models import Model
from wagtail.models.audit_log import BaseLogEntry
from wagtail.utils.registry import ObjectTypeRegistry

class LogFormatter:
    label: str
    message: str
    comment: str
    def format_message(self, log_entry: BaseLogEntry) -> str: ...
    def format_comment(self, log_entry: BaseLogEntry) -> str: ...

class LogContext:
    user: AbstractBaseUser | None
    uuid: uuid.UUID | None
    def __init__(self, user: AbstractBaseUser | None = None, generate_uuid: bool = True) -> None: ...
    def __enter__(self) -> Self: ...
    def __exit__(
        self, type: type[BaseException] | None, value: BaseException | None, traceback: types.TracebackType | None
    ) -> None: ...

empty_log_context: LogContext

def activate(log_context: LogContext) -> None: ...
def deactivate() -> None: ...
def get_active_log_context() -> LogContext: ...

class LogActionRegistry:
    has_scanned_for_actions: bool
    formatters: dict[str, LogFormatter]
    choices: list[tuple[str, str]]
    log_entry_models_by_type: ObjectTypeRegistry
    log_entry_models: set[type[Model]]
    def __init__(self) -> None: ...
    def scan_for_actions(self) -> None: ...
    def register_model(self, cls: type, log_entry_model: type[Model]) -> None: ...
    def register_action(self, action: str, *args: str) -> Callable[[type[LogFormatter]], None] | None: ...
    def get_choices(self) -> list[tuple[str, str]]: ...
    def get_formatter(self, log_entry: BaseLogEntry) -> LogFormatter | None: ...
    def action_exists(self, action: str) -> bool: ...
    def get_log_entry_models(self) -> set[type[Model]]: ...
    def get_action_label(self, action: str) -> str: ...
    def get_log_model_for_model(self, model: type) -> type[Model] | None: ...
    def get_log_model_for_instance(self, instance: Model) -> type[Model] | None: ...
    def log(
        self,
        instance: Model,
        action: str,
        user: AbstractBaseUser | None = None,
        uuid: uuid.UUID | None = None,
        **kwargs: Any,
    ) -> BaseLogEntry: ...
    def get_logs_for_instance(self, instance: Model) -> Any: ...  # TODO: genuinely dynamic (QuerySet or none())

registry: LogActionRegistry

def log(instance: Model, action: str, **kwargs: Any) -> BaseLogEntry: ...
