import unicodedata
import re
import json
from typing import Dict, Any, Optional
from jinja2.nativetypes import NativeEnvironment
from jinja2_strcase.jinja2_strcase import (
    to_camel,
    to_lower_camel,
    to_kebab,
    to_screaming_kebab,
    to_snake,
    to_screaming_snake,
    to_delimited,
    to_screaming_delimited,
)
from functools import wraps

def unidecode(value: str) -> str:
  return "".join(c for c in unicodedata.normalize("NFD", value) if unicodedata.category(c) != "Mn")

def null_safe_filter(func):
    @wraps(func)
    def wrapper(self, value: Optional[str], *args, **kwargs):
        if value is None:
            return ""  # Retorna um valor padrão, como uma string vazia
        return func(self, value, *args, **kwargs)
    return wrapper

class DefaultFilters:
    @null_safe_filter
    def group_id_folder(self, value: Optional[str]):
        if value is None:
            return ""
        return str(value).replace(".", "/")

    @null_safe_filter
    def to_unidecode(self, value: Optional[str]):
        return unidecode(value)

    @null_safe_filter
    def _kebab(self, v: Optional[str]) -> str:
        return to_kebab(v).replace("--", "-")

    @null_safe_filter
    def _regex_replace(self, value: Optional[str], pattern: str, repl: str, count: int = 0, flags: int = 0) -> str:
        return re.sub(pattern, repl, value, count, flags)

    @null_safe_filter
    def _from_json_filter(self, value: Optional[str]):
        return json.loads(value)

    @null_safe_filter
    def _to_camel(self, value: Optional[str]) -> str:
        return to_camel(value)

    @null_safe_filter
    def _to_lower_camel(self, value: Optional[str]) -> str:
        return to_lower_camel(value)

    @null_safe_filter
    def _to_screaming_kebab(self, value: Optional[str]) -> str:
        return to_screaming_kebab(value)

    @null_safe_filter
    def _to_snake(self, value: Optional[str]) -> str:
        return to_snake(value)

    @null_safe_filter
    def _to_screaming_snake(self, value: Optional[str]) -> str:
        return to_screaming_snake(value)

    @null_safe_filter
    def _to_delimited(self, value: Optional[str], delimiter: str) -> str:
        return to_delimited(value, delimiter)

    @null_safe_filter
    def _to_screaming_delimited(self, value: Optional[str], delimiter) -> str:
        return to_screaming_delimited(value, delimiter)

    def create(self) -> Dict[str, Any]:
        return {
            "group_id_folder": self.group_id_folder,
            "to_unidecode": self.to_unidecode,
            "to_camel": self._to_camel,
            "to_lower_camel": self._to_lower_camel,
            "to_kebab": self._kebab,
            "to_screaming_kebab": self._to_screaming_kebab,
            "to_snake": self._to_snake,
            "to_screaming_snake": self._to_screaming_snake,
            "to_delimited": self._to_delimited,
            "to_screaming_delimited": self._to_screaming_delimited,
            "camelcase": self._to_lower_camel,
            "kebabcase": self._kebab,
            "macrocase": self._to_screaming_snake,
            "snakecase": self._to_snake,
            "pascalcase": self._to_camel,
            "cobolcase": self._to_screaming_kebab,
            "regex_replace": self._regex_replace,
            "from_json": self._from_json_filter,
        }

def __generate_jinja_env() -> NativeEnvironment:
  env = NativeEnvironment(
      keep_trailing_newline=True,
      trim_blocks=True,
      lstrip_blocks=True,
  )
  default_filters = DefaultFilters().create()
  env.filters = {**env.filters, **default_filters}
  return env

jinja_env = __generate_jinja_env()
