"""
KeeHook provides the namespace hook for the KeeSpace namespace class.
"""
#  AGPL-3.0 license
#  Copyright (c) 2025 Asger Jon Vistisen
from __future__ import annotations

from types import FunctionType as Func

from ..parse import maybe
from ..static import AbstractObject
from ..static import AbstractObject as Object
from ..text import typeMsg
from ..waitaminute import ReservedName
from ..mcls.hooks import AbstractHook

try:
  from typing import TYPE_CHECKING
except ImportError:
  try:
    from typing_extensions import TYPE_CHECKING
  except ImportError:
    TYPE_CHECKING = False

if TYPE_CHECKING:
  from typing import Any, Self, TypeAlias

  from . import KeeSpace, _AutoMember


class KeeHook(AbstractHook):
  """
  KeeHook provides the namespace hook for the KeeSpace namespace class.
  """

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  #  NAMESPACE  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  #  GETTERS  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  #  SETTERS  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  #  Python API   # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  #  CONSTRUCTORS   # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  #  DOMAIN SPECIFIC  # # # # # # # # # # # # # # # # # # # # # # # # # # # #
  # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #

  def _addMember(self, name: str, value: Any, **kwargs) -> None:
    """
    Add a member to the KeeSpace namespace.
    """
    if value is None:
      if kwargs.get('_recursion2', False):
        raise RecursionError
      return self._addMember(name, name, _recursion2=True)
    valueType = self._getValueType()
    if valueType is None:
      if kwargs.get('_recursion', False):
        raise RecursionError
      self._setValueType(type(value))
      return self._addMember(name, value, _recursion=True)
    else:
      if not isinstance(value, valueType):
        es = """Found inconsistent value type for members of the '%s' class 
        under construction. Member named: '%s' has value type: '%s', 
        while the previous values had value type: '%s'. Values passed to 
        'auto' must be of the same type for the same enumeration!"""
        clsName = self.space.getClassName()
        actName = type(value).__name__
        expName = valueType.__name__
        e = es % (clsName, name, actName, expName)
        raise NotImplementedError(e)
    existing = self.space.get('__future_entries__', {})
    if name in existing:
      raise NotImplementedError('duplicate keenum: %s' % name)
    existing[name] = value
    self.space['__future_entries__'] = existing

  def _setValueType(self, valueType: type, ) -> None:
    """
    Set the value type for the KeeSpace namespace.
    """
    if '__future_value_type__' in self.space:
      existingType = self.space['__future_value_type__']
      if valueType is not existingType:
        es = """Found inconsistent value type for members of the '%s' class 
        under construction. The value type was previously set to: '%s', 
        while the new value type is: '%s'. Values passed to 'auto' must be 
        of the same type for the same enumeration!"""
        clsName = self.space.getClassName()
        e = es % (clsName, existingType.__name__, valueType.__name__)
        raise NotImplementedError(e)
      return
    self.space['__future_value_type__'] = valueType

  def _getValueType(self) -> type:
    """
    Get the value type for the KeeSpace namespace.
    """
    return self.space.get('__future_value_type__', None)

  def setItemHook(self, key: str, value: Any, oldValue: Any, ) -> bool:
    """
    The setItemHook method is called when an item is set in the
    namespace.
    """
    if isinstance(value, AbstractObject):
      if hasattr(value, '__auto_member__'):
        if getattr(value, '__auto_member__'):
          if TYPE_CHECKING:
            assert isinstance(value, _AutoMember)
          self._addMember(key.upper(), value.getValue())
          return True
    return False

  def preCompileHook(self, compiledSpace: dict) -> dict:
    """Hook for preCompile. This is called before the __init__ method of
    the namespace object is called. The default implementation does nothing
    and returns the contents unchanged. """
    futureEntries = compiledSpace.get('__future_entries__', None)
    if futureEntries is None:
      compiledSpace['__future_entries__'] = dict()
    return compiledSpace
