"""Functions related to comparisons, didn't want to name the file tcr_test.py to avoid confusion with testing as in testing if code works."""

from collections.abc import Callable
from typing import Any


class AbleResult:
  """Contains a result from tcr.able().

  May be used in an if statement or bool(able_result) expression, in whichc ase
  """

  result: Any | BaseException
  truefalse: bool
  """Can't name it bool, can't name it result, can't name it anything... bruh. truefalse it is then"""

  def __init__(self, truefalse: bool, result: Any):
    self.truefalse = truefalse
    self.result = result

  def __bool__(self) -> bool:
    return self.truefalse

  def __iter__(self):
    yield self.truefalse
    yield self.result


def able(func: Callable, *args, able_exception__: BaseException = Exception, **kwargs) -> AbleResult:
  """### Return True* if x is func(x)-able aka does not raise any errors while passed in to func otherwise return False*.

  *The result type is AbleResult, not bool, but it's bool-able (can be used in an if statement or bool(able_result) normally)

  #### Example:
  ```py
  >>> able(int, '1') # Wouldn't raise any Exception
  True
  >>> able(int, 'a') # Would raise: ValueError: invalid literal for int() with base 10: 'a'
  False
  >>> [int(x) for x in [] if able(int, x)]
  ```

  #### Result retrieving example:
  ```py
  >>> color = 'ff8000' # a hex encoded color code
  >>> if (r := able(int, color, base=16)):
  ...   print(repr(r.result))
  16744448
  >>> color = 'ff8000'
  >>> if (r := able(int, color)) or True: # oops! forgot to set the base (and added or True so this example actually prints)
  ...   print(repr(r.result)) # Returns False along with the exception in the result field
  ValueError("invalid literal for int() with base 10: 'ff8000'")
  ```
  """
  try:
    result = func(*args, **kwargs)
  except able_exception__ as e:
    return AbleResult(False, e)
  else:
    return AbleResult(True, result)


def isdunder(s: str):
  """Return True if the string ends and starts with at least two underscores each.

  A 2-char string containing just underscores is considered dunder.
  """

  return s.startswith('__') and (s.endswith('__'))
