import ipaddress
from typing import Any

import safe_radix32


def maybe_rad32(maybe_int: Any) -> str:
    """
    Use this where it does not matter too much if the argument is validly convertible to safe-radix,
    but it must never fail. When logging an exception for example.
    """
    if isinstance(maybe_int, int):
        try:
            return safe_radix32.encode_fw(maybe_int)
        except Exception:
            pass
    return str(maybe_int)


class AccessLoggableError(Exception):
    """
    Created to make nicely unified error and access logging possible.
    """

    @classmethod
    def format_message(cls, error_code: int, message=None, account_id=None, maybe_account=False, ip_address=None):
        log = []
        # identity
        if ip_address:
            try:
                ip_address = ipaddress.ip_address(ip_address).compressed
            except Exception:
                ip_address = repr(ip_address)
        if account_id is None:
            pass
        elif account_id == 0:
            log.append(f"anonymous from {ip_address}: " if ip_address else "anonymous: ")
        else:
            if maybe_account:
                log.append(f"maybe {maybe_rad32(account_id)}")
            else:
                log.append(f"{maybe_rad32(account_id)}")
            if ip_address:
                log.append(f" from {ip_address}")
            log.append(": ")
        # subject
        if error_code:
            if message:
                log.append(f"{error_code} {message}")
            else:
                log.append(str(error_code))
        elif message:  # no error code means this for something successful
            log.append(message)
        else:
            log.append("Success")
        return "".join(log)

    def __init__(self, error_code: int, *args, **kwargs):
        Exception.__init__(self, error_code, self.format_message(error_code, *args, **kwargs))

    @property
    def code(self):
        return self.args[0]

    @property
    def log(self):
        return self.args[1]
