# retoor <retoor@molodetz.nl>

from .core import TTLCache, bump_cache_version, datetime, db, get_table, sync_local_cache, timezone
from .settings import get_int_setting, set_setting
from .soft_delete import soft_delete


NOTIFICATION_TYPES = [
    {"key": "comment", "label": "Comments", "description": "Someone comments on your post"},
    {"key": "reply", "label": "Replies", "description": "Someone replies to your comment"},
    {"key": "thread", "label": "Thread activity", "description": "Someone else comments on a post you've commented on"},
    {"key": "mention", "label": "Mentions", "description": "Someone mentions you with @username"},
    {"key": "vote", "label": "Upvotes", "description": "Someone ++'d your content"},
    {"key": "follow", "label": "Followers", "description": "Someone starts following you"},
    {"key": "message", "label": "Direct messages", "description": "Someone sends you a message"},
    {"key": "badge", "label": "Badges", "description": "You earn a badge"},
    {"key": "level", "label": "Level-ups", "description": "You reach a new level"},
    {"key": "issue", "label": "Issue tracker", "description": "Updates on issue reports you filed"},
    {"key": "reminder", "label": "Reminders", "description": "A reminder or scheduled task you asked Devii to run fires"},
    {"key": "harvest_stolen", "label": "Farm raids", "description": "Someone steals a ready build from your Code Farm"},
    {"key": "award", "label": "Awards", "description": "Someone gives you an award on your profile"},
    {"key": "quiz_attempt", "label": "Quiz attempts", "description": "Someone completes one of your quizzes"},
    {"key": "battle", "label": "Opinion Wars", "description": "Lead changes, results and fight-ready alerts for battles you joined"},
    {"key": "workspace", "label": "Dev workspaces", "description": "Idle, quota, retention and moderation notices for your dev workspaces"},
    {"key": "moderation", "label": "Moderation", "description": "Acknowledgements for reports you file and decisions taken on your content"},
    {"key": "system", "label": "System alerts", "description": "Platform infrastructure alerts (e.g. the AI gateway going down)"},
]


NOTIFICATION_CHANNELS = ("in_app", "push", "telegram")


_NOTIFICATION_CHANNEL_COLUMNS = {
    "in_app": "in_app_enabled",
    "push": "push_enabled",
    "telegram": "telegram_enabled",
}


_NOTIFICATION_CHANNEL_DEFAULTS = {"in_app": 1, "push": 1, "telegram": 0}


_NOTIFICATION_TYPE_KEYS = {entry["key"] for entry in NOTIFICATION_TYPES}


_notification_prefs_cache = TTLCache(ttl=300, max_size=500)


def _notification_default(notification_type: str, channel: str) -> bool:
    fallback = _NOTIFICATION_CHANNEL_DEFAULTS.get(channel, 1)
    return get_int_setting(f"notif_default_{notification_type}_{channel}", fallback) != 0


def get_notification_default(notification_type: str, channel: str) -> bool:
    return _notification_default(notification_type, channel)


def set_notification_default(
    notification_type: str, channel: str, enabled: bool
) -> None:
    if channel not in _NOTIFICATION_CHANNEL_COLUMNS:
        raise ValueError(f"Unknown notification channel: {channel}")
    set_setting(f"notif_default_{notification_type}_{channel}", "1" if enabled else "0")


def _notification_overrides(user_uid: str) -> dict:
    sync_local_cache("notif_prefs", _notification_prefs_cache)
    cached = _notification_prefs_cache.get(user_uid)
    if cached is not None:
        return cached
    overrides: dict = {}
    if "notification_preferences" in db.tables:
        for row in db["notification_preferences"].find(
            user_uid=user_uid, deleted_at=None
        ):
            overrides[row["notification_type"]] = {
                channel: bool(
                    row.get(column, _NOTIFICATION_CHANNEL_DEFAULTS.get(channel, 1))
                )
                for channel, column in _NOTIFICATION_CHANNEL_COLUMNS.items()
            }
    _notification_prefs_cache.set(user_uid, overrides)
    return overrides


def notification_enabled(user_uid: str, notification_type: str, channel: str) -> bool:
    if channel not in _NOTIFICATION_CHANNEL_COLUMNS:
        return True
    override = _notification_overrides(user_uid).get(notification_type)
    if override is not None:
        return bool(override[channel])
    return _notification_default(notification_type, channel)


def get_notification_prefs(user_uid: str) -> list:
    overrides = _notification_overrides(user_uid)
    result = []
    for entry in NOTIFICATION_TYPES:
        key = entry["key"]
        override = overrides.get(key)
        channels = {
            channel: bool(override[channel])
            if override
            else _notification_default(key, channel)
            for channel in _NOTIFICATION_CHANNEL_COLUMNS
        }
        result.append(
            {
                "key": key,
                "label": entry["label"],
                "description": entry["description"],
                **channels,
                "customized": override is not None,
            }
        )
    return result


def set_notification_pref(
    user_uid: str, notification_type: str, channel: str, enabled: bool
) -> dict:
    if notification_type not in _NOTIFICATION_TYPE_KEYS:
        raise ValueError(f"Unknown notification type: {notification_type}")
    if channel not in _NOTIFICATION_CHANNEL_COLUMNS:
        raise ValueError(f"Unknown notification channel: {channel}")
    from devplacepy.utils import generate_uid

    table = get_table("notification_preferences")
    now = datetime.now(timezone.utc).isoformat()
    existing = table.find_one(user_uid=user_uid, notification_type=notification_type)
    if existing:
        values = {
            name: bool(
                existing.get(column, _NOTIFICATION_CHANNEL_DEFAULTS.get(name, 1))
            )
            for name, column in _NOTIFICATION_CHANNEL_COLUMNS.items()
        }
    else:
        values = {
            name: _notification_default(notification_type, name)
            for name in _NOTIFICATION_CHANNEL_COLUMNS
        }
    values[channel] = enabled
    columns = {
        column: 1 if values[name] else 0
        for name, column in _NOTIFICATION_CHANNEL_COLUMNS.items()
    }
    if existing:
        record = {
            "id": existing["id"],
            **columns,
            "updated_at": now,
            "deleted_at": None,
            "deleted_by": None,
        }
        table.update(record, ["id"])
        result = {**existing, **record}
    else:
        result = {
            "uid": generate_uid(),
            "user_uid": user_uid,
            "notification_type": notification_type,
            **columns,
            "created_at": now,
            "updated_at": now,
            "deleted_at": None,
            "deleted_by": None,
        }
        table.insert(result)
    bump_cache_version("notif_prefs")
    return result


def reset_notification_prefs(user_uid: str, deleted_by: str | None = None) -> int:
    if "notification_preferences" not in db.tables:
        return 0
    count = soft_delete(
        "notification_preferences", deleted_by or f"user:{user_uid}", user_uid=user_uid
    )
    bump_cache_version("notif_prefs")
    return int(count)


def mark_notifications_read_by_target(user_uid: str, target_url: str) -> int:
    if not user_uid or not target_url or "notifications" not in db.tables:
        return 0
    notifications_table = get_table("notifications")
    ids = [
        n["id"]
        for n in notifications_table.find(user_uid=user_uid, read=False)
        if n.get("target_url")
        and (
            n["target_url"] == target_url
            or n["target_url"].startswith(f"{target_url}#")
        )
    ]
    if not ids:
        return 0
    with db:
        for notification_id in ids:
            notifications_table.update({"id": notification_id, "read": True}, ["id"])
    from devplacepy.templating import clear_unread_cache

    clear_unread_cache(user_uid)
    return len(ids)
