from objict import objict

META_KEYS = ["SERVER_PROTOCOL", "REQUEST_METHOD", "QUERY_STRING", "HTTP_USER_AGENT"]


def event(category, description, level=10, request=None, **kwargs):
    from taskqueue.models import Task
    data = objict(category=category, description=description, level=level)
    data.metadata = objict.fromdict(kwargs)
    Task.Publish("incident", "new_event", channel="tq_app_handler", data=data)


def event_now(category, description, level=10, request=None, **kwargs):
    from .models.event import Event
    data = objict(category=category, description=description, level=level)
    data.metadata = objict.fromdict(kwargs)
    if request is not None:
        data.metadata.ip = request.ip
        if "path" not in data.metadata:
            data.metadata.path = request.path
        for key in META_KEYS:
            value = request.META.get(key, None)
            if value is not None and isinstance(value, str) and "." not in key:
                data.metadata[key.lower()] = str(value)
    if "hostname" in data.metadata:
        data.hostname = data.metadata.hostname
    if "details" in data.metadata:
        data.details = data.metadata.details
    if "component" in data.metadata:
        data.component = data.metadata.component
    if "component_id" in data.metadata:
        data.component_id = data.metadata.component_id
    if "ip" in data.metadata:
        data.reporter_ip = data.metadata.ip
    Event.createFromDict(None, data)


def exception_event(request, error, body=None, stack=None, title="REST Error"):
    from rest import settings
    import traceback
    if stack is None:
        stack = str(traceback.format_exc())
    host = request.get_host()
    server = settings.get("HOSTNAME", "unknown")
    if body is None:
        try:
            body = request.body.decode('utf-8')
        except Exception:
            body = request.DATA.asDict()
    subject = f"{title}: {host} - {error}"
    username = "anonymous"
    if request.member:
        username = request.member.username

    metadata = {
        "method": request.method,
        "path": request.path,
        "server": server,
        "error": str(error),
        "stack": stack,
        "username": username,
        "ip": request.ip,
    }

    if request.auth_model is not None:
        metadata['auth_model'] = str(request.auth_model)
    if request.group is not None:
        metadata['group'] = request.group.name

    if hasattr(request, "_log_component"):
        metadata["component"] = request._log_component
        metadata["pkey"] = request._log_pk

    event_now(
        "rest_errors", description=subject, level=1, hostname=host,
        details=stack, reporter_ip=request.ip, request=request,
        metadata=metadata)
