# retoor <retoor@molodetz.nl>

from datetime import datetime, timezone
from fastapi.templating import Jinja2Templates
from markupsafe import Markup, escape
from devplacepy.cache import TTLCache
from devplacepy.config import STATIC_VERSION, TEMPLATES_DIR, TEMPLATE_AUTO_RELOAD
from devplacepy.constants import TOPICS, REACTION_EMOJI
from devplacepy.database import get_int_setting, get_setting, get_table
from devplacepy.avatar import avatar_url
from devplacepy.utils import format_date as _format_date
from devplacepy.utils import time_ago as _time_ago
from devplacepy.utils import get_badge, is_admin, pretty_json
from devplacepy.attachments import format_file_size, file_icon_emoji
from devplacepy.content import is_owner as _owns
from devplacepy.customization import custom_css_tag, custom_js_tag, page_type_for

templates = Jinja2Templates(directory=str(TEMPLATES_DIR))
templates.env.auto_reload = TEMPLATE_AUTO_RELOAD


def is_self(user, uid) -> bool:
    return bool(user) and user["uid"] == uid


def guest_disabled(user):
    if user:
        return Markup("")
    return Markup(' disabled aria-disabled="true" title="Log in to participate"')


def login_hint(user):
    if user:
        return Markup("")
    return Markup('<a href="/auth/login" class="login-hint">Log in to participate</a>')


def static_url(path):
    if not isinstance(path, str):
        return path
    if not path.startswith("/static/") or path.startswith("/static/uploads/"):
        return path
    return f"/static/v{STATIC_VERSION}{path[len('/static'):]}"


templates.env.globals["static_url"] = static_url
templates.env.globals["static_version"] = STATIC_VERSION
templates.env.globals["is_admin"] = is_admin
templates.env.globals["owns"] = _owns
templates.env.globals["is_self"] = is_self
templates.env.globals["guest_disabled"] = guest_disabled
templates.env.globals["login_hint"] = login_hint

from devplacepy.docs_devrant import devrant_endpoints

templates.env.globals["devrant_endpoints"] = devrant_endpoints

_unread_cache = TTLCache(ttl=10, max_size=1000)
_messages_cache = TTLCache(ttl=10, max_size=1000)


def clear_unread_cache(user_uid: str) -> None:
    _unread_cache.pop(user_uid)


def clear_messages_cache(user_uid: str) -> None:
    _messages_cache.pop(user_uid)


def _cached_count(cache: TTLCache, table_name: str, cache_key: str, **filters) -> int:
    cached = cache.get(cache_key)
    if cached is not None:
        return cached
    table = get_table(table_name)
    count = table.count(**filters)
    cache.set(cache_key, count)
    return count


def jinja_unread_count(user_uid: str) -> int:
    return _cached_count(_unread_cache, "notifications", user_uid, user_uid=user_uid, read=False)


def jinja_unread_messages(user_uid: str) -> int:
    return _cached_count(_messages_cache, "messages", user_uid, receiver_uid=user_uid, read=False)


def jinja_user_projects(user_uid: str) -> list:
    projects = get_table("projects")
    return list(projects.find(user_uid=user_uid))


templates.env.globals["get_unread_count"] = jinja_unread_count
templates.env.globals["get_unread_messages"] = jinja_unread_messages
templates.env.globals["get_user_projects"] = jinja_user_projects
templates.env.globals["avatar_url"] = avatar_url
templates.env.globals["format_date"] = _format_date


def _normalize_iso(dt_str: str) -> str | None:
    try:
        parsed = datetime.fromisoformat(dt_str)
    except (ValueError, TypeError):
        return None
    if parsed.tzinfo is None:
        parsed = parsed.replace(tzinfo=timezone.utc)
    return parsed.isoformat()


def local_dt(dt_str: str, mode: str = "datetime") -> Markup:
    if not dt_str:
        return Markup("")
    iso = _normalize_iso(dt_str)
    if iso is None:
        return Markup(escape(dt_str))
    if mode == "ago":
        fallback = _time_ago(dt_str)
    elif mode == "date":
        fallback = _format_date(dt_str)
    else:
        fallback = _format_date(dt_str, include_time=True)
    return Markup(
        f'<time datetime="{escape(iso)}" data-dt data-dt-mode="{escape(mode)}">'
        f"{escape(fallback)}</time>"
    )


templates.env.globals["local_dt"] = local_dt
templates.env.globals["dt_ago"] = lambda dt_str: local_dt(dt_str, "ago")
templates.env.globals["badge_info"] = get_badge
templates.env.globals["TOPICS"] = TOPICS
templates.env.globals["REACTION_EMOJI"] = REACTION_EMOJI


def jinja_max_upload_size_mb():
    return get_int_setting("max_upload_size_mb", 10)


def jinja_max_attachments():
    return get_int_setting("max_attachments_per_resource", 10)


def jinja_allowed_file_types():
    return get_setting("allowed_file_types", "")


templates.env.globals["max_upload_size_mb"] = jinja_max_upload_size_mb
templates.env.globals["max_attachments_per_resource"] = jinja_max_attachments
templates.env.globals["allowed_file_types"] = jinja_allowed_file_types

_LANGUAGE_NAMES = {
    "python": "Python",
    "javascript": "JavaScript",
    "typescript": "TypeScript",
    "html": "HTML",
    "css": "CSS",
    "c": "C",
    "cpp": "C++",
    "java": "Java",
    "go": "Go",
    "rust": "Rust",
    "sql": "SQL",
    "bash": "Bash",
    "yaml": "YAML",
    "json": "JSON",
    "markdown": "Markdown",
    "swift": "Swift",
    "php": "PHP",
    "ruby": "Ruby",
    "kotlin": "Kotlin",
    "lua": "Lua",
    "perl": "Perl",
    "haskell": "Haskell",
    "elixir": "Elixir",
    "r": "R",
    "dart": "Dart",
    "scala": "Scala",
    "plaintext": "Plain Text",
}


def jinja_language_name(code: str) -> str:
    return _LANGUAGE_NAMES.get(code, code)


templates.env.globals["language_name"] = jinja_language_name
templates.env.globals["pretty_json"] = pretty_json

templates.env.globals["format_file_size"] = format_file_size
templates.env.globals["file_icon_emoji"] = file_icon_emoji

templates.env.globals["custom_css_tag"] = custom_css_tag
templates.env.globals["custom_js_tag"] = custom_js_tag
templates.env.globals["page_type_for"] = page_type_for
