# retoor <retoor@molodetz.nl>

from typing import Optional

from devplacepy.attachments import get_attachments_batch
from devplacepy.database import (
    get_table,
    get_users_by_uids,
    get_user_votes,
    get_vote_counts,
    get_comment_counts_by_post_uids,
    get_user_stars,
    text_search_clause,
)
from devplacepy.services.devrant.serializers import serialize_rant, serialize_comment

SORT_ORDER = {
    "recent": ["-created_at"],
    "top": ["-stars", "-created_at"],
    "algo": ["-stars", "-created_at"],
}


def _score_maps(user_uids: list) -> dict:
    return {uid: get_user_stars(uid) for uid in set(user_uids)}


def build_rant_list(posts: list, viewer: Optional[dict]) -> list:
    post_uids = [post["uid"] for post in posts]
    user_uids = [post["user_uid"] for post in posts]
    authors = get_users_by_uids(list(set(user_uids)))
    user_scores = _score_maps(user_uids)
    my_votes = get_user_votes(viewer["uid"], post_uids) if viewer else {}
    comment_counts = get_comment_counts_by_post_uids(post_uids)
    attachments = get_attachments_batch("post", post_uids)
    return [
        serialize_rant(
            post,
            authors=authors,
            comment_counts=comment_counts,
            user_scores=user_scores,
            my_votes=my_votes,
            attachments=attachments,
            viewer=viewer,
        )
        for post in posts
    ]


def list_rants(sort: str, limit: int, skip: int, viewer: Optional[dict]) -> list:
    order = SORT_ORDER.get(sort, SORT_ORDER["recent"])
    posts = list(
        get_table("posts").find(
            deleted_at=None, order_by=order, _limit=limit, _offset=skip
        )
    )
    return build_rant_list(posts, viewer)


def search_rants(term: str, viewer: Optional[dict], limit: int = 50) -> list:
    posts_table = get_table("posts")
    clause = text_search_clause(
        posts_table, term, ("title", "content"), author_field="user_uid"
    )
    if clause is None:
        return []
    posts = list(
        posts_table.find(
            clause, deleted_at=None, order_by=["-created_at"], _limit=limit
        )
    )
    return build_rant_list(posts, viewer)


def load_rant_detail(post: dict, viewer: Optional[dict]) -> dict:
    rant = build_rant_list([post], viewer)[0]
    comments = list(
        get_table("comments").find(
            target_type="post",
            target_uid=post["uid"],
            deleted_at=None,
            order_by=["created_at"],
        )
    )
    comment_uids = [comment["uid"] for comment in comments]
    user_uids = [comment["user_uid"] for comment in comments]
    authors = get_users_by_uids(list(set(user_uids)))
    user_scores = _score_maps(user_uids)
    ups, downs = get_vote_counts(comment_uids)
    score_map = {uid: ups.get(uid, 0) - downs.get(uid, 0) for uid in comment_uids}
    my_votes = get_user_votes(viewer["uid"], comment_uids) if viewer else {}
    serialized = [
        serialize_comment(
            comment,
            int(post["id"]),
            authors=authors,
            user_scores=user_scores,
            my_votes=my_votes,
            score_map=score_map,
        )
        for comment in comments
    ]
    return {"rant": rant, "comments": serialized}
