"""Information about Python operators"""

from __future__ import annotations

from typing import Final

# Map from binary operator id to related method name (in Python 3).
op_methods: Final = {
    "+": "__add__",
    "-": "__sub__",
    "*": "__mul__",
    "/": "__truediv__",
    "%": "__mod__",
    "divmod": "__divmod__",
    "//": "__floordiv__",
    "**": "__pow__",
    "@": "__matmul__",
    "&": "__and__",
    "|": "__or__",
    "^": "__xor__",
    "<<": "__lshift__",
    ">>": "__rshift__",
    "==": "__eq__",
    "!=": "__ne__",
    "<": "__lt__",
    ">=": "__ge__",
    ">": "__gt__",
    "<=": "__le__",
    "in": "__contains__",
}

op_methods_to_symbols: Final = {v: k for (k, v) in op_methods.items()}

ops_falling_back_to_cmp: Final = {"__ne__", "__eq__", "__lt__", "__le__", "__gt__", "__ge__"}


ops_with_inplace_method: Final = {
    "+",
    "-",
    "*",
    "/",
    "%",
    "//",
    "**",
    "@",
    "&",
    "|",
    "^",
    "<<",
    ">>",
}

inplace_operator_methods: Final = {"__i" + op_methods[op][2:] for op in ops_with_inplace_method}

reverse_op_methods: Final = {
    "__add__": "__radd__",
    "__sub__": "__rsub__",
    "__mul__": "__rmul__",
    "__truediv__": "__rtruediv__",
    "__mod__": "__rmod__",
    "__divmod__": "__rdivmod__",
    "__floordiv__": "__rfloordiv__",
    "__pow__": "__rpow__",
    "__matmul__": "__rmatmul__",
    "__and__": "__rand__",
    "__or__": "__ror__",
    "__xor__": "__rxor__",
    "__lshift__": "__rlshift__",
    "__rshift__": "__rrshift__",
    "__eq__": "__eq__",
    "__ne__": "__ne__",
    "__lt__": "__gt__",
    "__ge__": "__le__",
    "__gt__": "__lt__",
    "__le__": "__ge__",
}

reverse_op_method_names: Final = set(reverse_op_methods.values())

# Suppose we have some class A. When we do A() + A(), Python will only check
# the output of A().__add__(A()) and skip calling the __radd__ method entirely.
# This shortcut is used only for the following methods:
op_methods_that_shortcut: Final = {
    "__add__",
    "__sub__",
    "__mul__",
    "__truediv__",
    "__mod__",
    "__divmod__",
    "__floordiv__",
    "__pow__",
    "__matmul__",
    "__and__",
    "__or__",
    "__xor__",
    "__lshift__",
    "__rshift__",
}

normal_from_reverse_op: Final = {m: n for n, m in reverse_op_methods.items()}
reverse_op_method_set: Final = set(reverse_op_methods.values())

unary_op_methods: Final = {"-": "__neg__", "+": "__pos__", "~": "__invert__"}

int_op_to_method: Final = {
    "==": int.__eq__,
    "is": int.__eq__,
    "<": int.__lt__,
    "<=": int.__le__,
    "!=": int.__ne__,
    "is not": int.__ne__,
    ">": int.__gt__,
    ">=": int.__ge__,
}

flip_ops: Final = {"<": ">", "<=": ">=", ">": "<", ">=": "<="}
neg_ops: Final = {
    "==": "!=",
    "!=": "==",
    "is": "is not",
    "is not": "is",
    "<": ">=",
    "<=": ">",
    ">": "<=",
    ">=": "<",
}
