# retoor <retoor@molodetz.nl>

from .core import _in_clause, db, defaultdict
from .users import get_users_by_uids
from .relations import get_blocked_uids
from .engagement import get_reactions_by_targets, get_user_votes, get_vote_counts


def _drop_blocked(raw, user):
    if not user:
        return raw
    blocked = get_blocked_uids(user["uid"])
    if not blocked:
        return raw
    return [c for c in raw if c["user_uid"] not in blocked]


def _build_comment_items(raw, user=None):
    uids = [c["user_uid"] for c in raw]
    cids = [c["uid"] for c in raw]
    users = get_users_by_uids(uids)
    ups, downs = get_vote_counts(cids)
    user_votes = get_user_votes(user["uid"], cids) if user else {}
    reactions = get_reactions_by_targets("comment", cids, user)
    from devplacepy.utils import time_ago
    from devplacepy.attachments import get_attachments_batch as _gab

    atts_map = _gab("comment", cids) if "attachments" in db.tables else {}
    items = {}
    for c in raw:
        items[c["uid"]] = {
            "comment": c,
            "author": users.get(c["user_uid"]),
            "time_ago": time_ago(c["created_at"]),
            "votes": {"up": ups.get(c["uid"], 0), "down": downs.get(c["uid"], 0)},
            "my_vote": user_votes.get(c["uid"], 0),
            "children": [],
            "attachments": atts_map.get(c["uid"], []),
            "reactions": reactions.get(c["uid"], {"counts": {}, "mine": []}),
        }
    return items


def load_comments(target_type, target_uid, user=None):
    if "comments" not in db.tables:
        return []
    comments_table = db["comments"]
    raw = list(
        comments_table.find(
            target_type=target_type,
            target_uid=target_uid,
            deleted_at=None,
            order_by=["created_at"],
        )
    )
    if not raw and target_type == "post":
        raw = list(
            comments_table.find(
                post_uid=target_uid, deleted_at=None, order_by=["created_at"]
            )
        )
    raw = _drop_blocked(raw, user)
    if not raw:
        return []
    cmap = _build_comment_items(raw, user)
    top = []
    for item in cmap.values():
        parent = item["comment"].get("parent_uid")
        if parent and parent in cmap:
            cmap[parent]["children"].append(item)
        else:
            top.append(item)
    return top


def get_recent_comments_by_target_uids(target_type, target_uids, limit=3, user=None):
    if not target_uids or "comments" not in db.tables:
        return {}
    placeholders, params = _in_clause(target_uids)
    params["tt"] = target_type
    params["lim"] = limit
    raw = list(
        db.query(
            f"SELECT * FROM ("
            f"  SELECT *, ROW_NUMBER() OVER ("
            f"    PARTITION BY target_uid ORDER BY created_at DESC, id DESC"
            f"  ) AS rn FROM comments"
            f"  WHERE target_type=:tt AND target_uid IN ({placeholders}) AND deleted_at IS NULL"
            f") WHERE rn <= :lim ORDER BY target_uid, created_at ASC",
            **params,
        )
    )
    raw = _drop_blocked(raw, user)
    if not raw:
        return {}
    items = _build_comment_items(raw, user)
    by_target = defaultdict(list)
    for c in raw:
        by_target[c["target_uid"]].append(c)
    result = {}
    for target_uid, group in by_target.items():
        in_group = {c["uid"] for c in group}
        top = []
        for c in group:
            item = items[c["uid"]]
            item["children"] = []
        for c in group:
            item = items[c["uid"]]
            parent = c.get("parent_uid")
            if parent and parent in in_group:
                items[parent]["children"].append(item)
            else:
                top.append(item)
        result[target_uid] = top
    return result


def get_recent_comments_by_post_uids(post_uids, limit=3, user=None):
    return get_recent_comments_by_target_uids("post", post_uids, limit, user)


def load_comments_by_target_uids(target_type, target_uids, user=None):
    if not target_uids or "comments" not in db.tables:
        return {}
    placeholders, params = _in_clause(target_uids)
    params["tt"] = target_type
    raw = list(
        db.query(
            f"SELECT * FROM comments WHERE target_type=:tt AND target_uid IN ({placeholders}) AND deleted_at IS NULL ORDER BY created_at",
            **params,
        )
    )
    raw = _drop_blocked(raw, user)
    if not raw:
        return {}
    from collections import defaultdict
    by_uid = defaultdict(list)
    for c in raw:
        by_uid[c["target_uid"]].append(c)
    result = {}
    for uid in target_uids:
        group = by_uid.get(uid, [])
        if not group:
            result[uid] = []
            continue
        cmap = _build_comment_items(group, user)
        tree = []
        for item in cmap.values():
            parent = item["comment"].get("parent_uid")
            if parent and parent in cmap:
                cmap[parent]["children"].append(item)
            else:
                tree.append(item)
        result[uid] = tree
    return result
