# retoor <retoor@molodetz.nl>

from __future__ import annotations

import time
from datetime import datetime, timedelta, timezone
from typing import Optional

from devplacepy.config import (
    PRESENCE_ONLINE_LIMIT,
    PRESENCE_ONLINE_MARGIN_SECONDS,
    PRESENCE_TIMEOUT_SECONDS,
    PRESENCE_TRACK_LIMIT,
    PRESENCE_WRITE_SECONDS,
)
from devplacepy.database import get_online_users, set_last_seen

_last_write: dict[str, float] = {}


def recording_allowed(user_uid: str) -> bool:
    from devplacepy.database import consent_granted

    return bool(user_uid) and consent_granted("user", user_uid, "activity_recording")


def touch(user_uid: str) -> None:
    if not user_uid:
        return
    now = time.monotonic()
    if now - _last_write.get(user_uid, 0.0) < PRESENCE_WRITE_SECONDS:
        return
    _last_write[user_uid] = now
    if not recording_allowed(user_uid):
        return
    set_last_seen(user_uid, datetime.now(timezone.utc).isoformat())


def seconds_since(last_seen: Optional[str]) -> Optional[float]:
    if not last_seen:
        return None
    try:
        seen = datetime.fromisoformat(last_seen)
    except (ValueError, TypeError):
        return None
    if seen.tzinfo is None:
        seen = seen.replace(tzinfo=timezone.utc)
    return (datetime.now(timezone.utc) - seen).total_seconds()


def stays_online(elapsed: Optional[float], was_online: bool) -> bool:
    if elapsed is None:
        return False
    grace = PRESENCE_TIMEOUT_SECONDS + PRESENCE_ONLINE_MARGIN_SECONDS
    return elapsed < (grace if was_online else PRESENCE_TIMEOUT_SECONDS)


def is_online(user: Optional[dict]) -> bool:
    if not user:
        return False
    return stays_online(seconds_since(user.get("last_seen")), was_online=False)


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


def online_cutoff_iso() -> str:
    return _cutoff_iso(PRESENCE_TIMEOUT_SECONDS)


def sort_by_username(rows: list) -> list:
    return sorted(rows, key=lambda row: (row.get("username") or "").lower())


def online_users(limit: int = PRESENCE_ONLINE_LIMIT) -> list:
    return sort_by_username(get_online_users(online_cutoff_iso(), limit))


def online_candidates(limit: int = PRESENCE_TRACK_LIMIT) -> list:
    return sort_by_username(
        get_online_users(
            _cutoff_iso(PRESENCE_TIMEOUT_SECONDS + PRESENCE_ONLINE_MARGIN_SECONDS), limit
        )
    )
