# retoor <retoor@molodetz.nl>

from datetime import datetime, timedelta, timezone

from devplacepy.cache import TTLCache
from devplacepy.config import (
    AWARD_DISPLAY_HOURS_DEFAULT,
    AWARD_GIVE_COOLDOWN_HOURS_DEFAULT,
    AWARD_RECEIVE_COOLDOWN_HOURS_DEFAULT,
)
from .core import db
from .pagination import build_pagination
from .settings import get_int_setting
from .core import get_table, _now_iso
from .users import get_users_by_uids
from .content import resolve_by_slug
from .soft_delete import soft_delete, soft_delete_in

AWARDS_PER_PAGE = 12


def _awards_table():
    return get_table("awards")


def award_give_cooldown_hours() -> int:
    return max(1, get_int_setting("award_give_cooldown_hours", AWARD_GIVE_COOLDOWN_HOURS_DEFAULT))


def award_receive_cooldown_hours() -> int:
    return max(
        1, get_int_setting("award_receive_cooldown_hours", AWARD_RECEIVE_COOLDOWN_HOURS_DEFAULT)
    )


def award_display_hours() -> int:
    return max(1, get_int_setting("award_display_hours", AWARD_DISPLAY_HOURS_DEFAULT))


def _cooldown_cutoff(hours: int) -> str:
    return (datetime.now(timezone.utc) - timedelta(hours=hours)).isoformat()


def has_giver_cooldown(giver_uid: str) -> bool:
    if not giver_uid or "awards" not in db.tables:
        return False
    cutoff = _cooldown_cutoff(award_give_cooldown_hours())
    row = _awards_table().find_one(
        giver_uid=giver_uid, deleted_at=None, created_at={">=": cutoff}
    )
    return row is not None


def has_receiver_cooldown(receiver_uid: str) -> bool:
    if not receiver_uid or "awards" not in db.tables:
        return False
    cutoff = _cooldown_cutoff(award_receive_cooldown_hours())
    row = _awards_table().find_one(
        receiver_uid=receiver_uid, deleted_at=None, created_at={">=": cutoff}
    )
    return row is not None


def can_receive_award(receiver_uid: str) -> bool:
    return not has_receiver_cooldown(receiver_uid)


def can_give_award(giver_uid: str, receiver_uid: str) -> bool:
    if not giver_uid or not receiver_uid or giver_uid == receiver_uid:
        return False
    return not has_giver_cooldown(giver_uid) and not has_receiver_cooldown(receiver_uid)


def _published_filter():
    return {"deleted_at": None, "generated_at": {">": ""}}


def count_published_awards(receiver_uid: str) -> int:
    if not receiver_uid or "awards" not in db.tables:
        return 0
    return _awards_table().count(receiver_uid=receiver_uid, **_published_filter())


def _latest_published(receiver_uid: str):
    if not receiver_uid or "awards" not in db.tables:
        return None
    rows = list(
        _awards_table().find(
            receiver_uid=receiver_uid,
            deleted_at=None,
            generated_at={">": ""},
            order_by=["-generated_at"],
            _limit=1,
        )
    )
    return rows[0] if rows else None


def recompute_user_award_stats(receiver_uid: str) -> None:
    if not receiver_uid or "users" not in db.tables:
        return
    count = count_published_awards(receiver_uid)
    latest = _latest_published(receiver_uid)
    users = get_table("users")
    payload = {
        "uid": receiver_uid,
        "award_count": count,
        "last_award_at": latest.get("generated_at") if latest else None,
        "last_award_slug": latest.get("slug") if latest else None,
        "last_award_uid": latest.get("uid") if latest else None,
    }
    users.update(payload, ["uid"])


_prominence_cache = TTLCache(ttl=15, max_size=500)


def award_is_prominent(user: dict | None) -> bool:
    if not user or not user.get("last_award_at") or not user.get("last_award_uid"):
        return False
    cached = _prominence_cache.get(user["last_award_uid"])
    if cached is not None:
        return cached
    prominent = _compute_prominence(user["last_award_uid"])
    _prominence_cache.set(user["last_award_uid"], prominent)
    return prominent


def _compute_prominence(award_uid: str) -> bool:
    award = resolve_by_slug(_awards_table(), award_uid)
    if not award or not award.get("generated_at"):
        return False
    try:
        published = datetime.fromisoformat(award["generated_at"])
        if published.tzinfo is None:
            published = published.replace(tzinfo=timezone.utc)
    except (ValueError, TypeError):
        return False
    window = timedelta(hours=award_display_hours())
    return datetime.now(timezone.utc) - published <= window


def enrich_award(row: dict, givers: dict | None = None) -> dict:
    item = dict(row)
    giver_uid = row.get("giver_uid", "")
    giver = (givers or {}).get(giver_uid) or get_users_by_uids([giver_uid]).get(giver_uid)
    item["giver"] = giver
    item["image_url"] = f"/awards/{row.get('slug', '')}/256"
    item["thumb_url"] = f"/awards/{row.get('slug', '')}/64"
    return item


def get_user_awards(receiver_uid: str, page: int = 1, per_page: int = AWARDS_PER_PAGE):
    if not receiver_uid or "awards" not in db.tables:
        return [], build_pagination(page, 0, per_page)
    table = _awards_table()
    total = table.count(receiver_uid=receiver_uid, **_published_filter())
    offset = max(0, (page - 1) * per_page)
    rows = list(
        table.find(
            receiver_uid=receiver_uid,
            deleted_at=None,
            generated_at={">": ""},
            order_by=["-generated_at"],
            _limit=per_page,
            _offset=offset,
        )
    )
    giver_uids = [row.get("giver_uid") for row in rows if row.get("giver_uid")]
    givers = get_users_by_uids(giver_uids)
    items = [enrich_award(row, givers) for row in rows]
    return items, build_pagination(page, total, per_page)


def get_prominent_award(profile_user: dict) -> dict | None:
    if not award_is_prominent(profile_user):
        return None
    award = resolve_by_slug(_awards_table(), profile_user.get("last_award_uid", ""))
    if not award:
        return None
    return enrich_award(award)


def revoke_award(award_uid: str, admin_uid: str) -> dict | None:
    table = _awards_table()
    row = table.find_one(uid=award_uid)
    if not row or row.get("deleted_at"):
        return None
    stamp = _now_iso()
    attachment_uids = [
        uid
        for uid in (
            row.get("attachment_uid_512"),
            row.get("attachment_uid_256"),
            row.get("attachment_uid_64"),
        )
        if uid
    ]
    soft_delete("awards", admin_uid, stamp=stamp, uid=award_uid)
    from devplacepy.attachments import soft_delete_attachments_for

    soft_delete_attachments_for("award", [award_uid], admin_uid)
    if attachment_uids:
        soft_delete_in("attachments", "uid", attachment_uids, admin_uid, stamp=stamp)
    recompute_user_award_stats(row.get("receiver_uid", ""))
    return row