from typing import Any
import os

from ._sentinel import _no_value


LOG_DEBUG = "【Debug】 [File]: {file} [Line]: {lineno}, [Function]: `{func}`, "

LOG_FLAG = LOG_DEBUG + "[State]: Label `{label}` is {state}"

LOG_TRIG = LOG_DEBUG + "[Label]: `{label}`, [Action]: {action}"

LOG_VALUE = (
  LOG_DEBUG 
  + "[Label]: `{label}` (index {num}), [Flag]: {state}, [Value]: {value}"
)

LOG_VAR = (
  LOG_DEBUG 
  + "[Label]: `{label}` (index {num}), "
  "[Flag]: {state}, [Variable]: `{var}`, [Value]: {value}"
)


def _get_debug_info(self) -> str:
   func_name = self._frame.f_code.co_name

   if self._lineno is None:
      self._lineno = self._frame.f_lineno
   
   if self._file_name is None:
      self._file_name = self._frame.f_code.co_filename

   return func_name

def _get_var_info(
        self, label: str, index: int, inner_index: int=None,
) -> tuple[str, Any]:
   if inner_index is None:
       var_refs = self._var_list[label][index]
       org_value = self._org_value[label][index][0]
   else:
       var_refs = self._var_list[label][index][inner_index]
       org_value = self._org_value[label][index][inner_index]      
   

   return (var_refs[2],org_value)

def _print_flag_debug(
      self, label: str, state: str, clear: bool=True,
) -> None:
    func_name = self._get_debug_info()
    file = os.path.basename(self._file_name)

    print(
        LOG_FLAG.format(
           file=file, lineno=self._lineno, 
           func=func_name, label=label, state=state,
        )
    )

    if clear:
       self._clear_frame()


# for `switch_lit()`

def _print_val_debug(
      self, 
      label: str | list[str] | tuple[str, ...], index: int, 
      flag: bool, before: Any, after: Any=_no_value,
) -> None:
      func_name = self._get_debug_info()
      file = os.path.basename(self._file_name)

      if after is _no_value:
         print(
            LOG_VALUE.format(
               file=file, lineno=self._lineno, 
               func=func_name, label=label, num=index, 
               state=flag, value=repr(before),
            )
         )
      else:
         print(
            LOG_VALUE.format(
               file=file, lineno=self._lineno, 
               func=func_name, label=label, num=index, 
               state=flag, value=f"{repr(before)} -> {repr(after)}",
            )
         )

      self._clear_frame()


# for `switch_var()`

def _print_var_debug(
      self, label: str, index: int, flag: bool, 
      inner_index: int=None, new_value: Any=_no_value,
) -> None:
   func_name = self._get_debug_info()
   file = os.path.basename(self._file_name)

   # `var_value` is the original value of this variable
   (var_name, var_value) = self._get_var_info(label, index, inner_index)

   if new_value is _no_value:
         value = repr(var_value)
   elif type(var_value) != type(new_value) or var_value != new_value:
         value = f"{repr(var_value)} -> {repr(new_value)}"
   else:
         new = self._new_value[label][index]
         value = f"{repr(new)} -> {repr(new_value)}"

   print(
      LOG_VAR.format(
         file=file, lineno=self._lineno, 
         func=func_name, label=label, num=index, 
         state=flag, var=var_name, value=value,
      )
   )


# for `set_trigger()` and `revert()`

def _print_trig_debug(self, label: str, action: str) -> None:
    func_name = self._get_debug_info()
    file = os.path.basename(self._file_name)

    print(
        LOG_TRIG.format(
           file=file, lineno=self._lineno, func=func_name, 
           label=label, action=action,
        )
    )
    self._clear_frame()
