# retoor <retoor@molodetz.nl>

import json
from typing import Optional

from devplacepy.avatar import avatar_seed
from devplacepy.database import get_table
from devplacepy.services.devrant.avatar import avatar_payload
from devplacepy.services.devrant.ids import to_unix


def decode_tags(post: dict) -> list:
    raw = post.get("tags")
    if raw:
        try:
            value = json.loads(raw)
            if isinstance(value, list):
                return [str(tag) for tag in value]
        except (ValueError, TypeError):
            pass
    topic = post.get("topic")
    return [topic] if topic else []


def encode_tags(tags: list) -> str:
    cleaned = [str(tag).strip() for tag in tags if str(tag).strip()]
    return json.dumps(cleaned)


def _rant_project(post: dict) -> dict | None:
    project_uid = post.get("project_uid")
    if not project_uid:
        return None
    project = get_table("projects").find_one(uid=project_uid)
    if not project:
        return None
    slug = project.get("slug") or project["uid"]
    return {
        "uid": project["uid"],
        "name": project.get("title") or project.get("name", ""),
        "slug": slug,
        "url": f"/projects/{slug}",
    }


def rant_text(post: dict) -> str:
    title = (post.get("title") or "").strip()
    content = post.get("content") or ""
    if title:
        return f"{title}\n\n{content}"
    return content


def _image_url(post: dict, attachments: Optional[list]) -> str:
    if post.get("image"):
        return f"/static/uploads/{post['image']}"
    for attachment in attachments or []:
        if attachment.get("is_image"):
            return attachment.get("url") or ""
    return ""


def serialize_rant(
    post: dict,
    *,
    authors: dict,
    comment_counts: dict,
    user_scores: dict,
    my_votes: dict,
    attachments: Optional[dict] = None,
    viewer: Optional[dict] = None,
) -> dict:
    author = authors.get(post["user_uid"]) or {}
    uid = post["uid"]
    username = author.get("username") or ""
    project = _rant_project(post)
    return {
        "id": int(post["id"]),
        "text": rant_text(post),
        "score": int(post.get("stars") or 0),
        "created_time": to_unix(post.get("created_at")),
        "attached_image": _image_url(post, (attachments or {}).get(uid)),
        "num_comments": int(comment_counts.get(uid, 0)),
        "tags": decode_tags(post),
        "vote_state": int(my_votes.get(uid, 0)),
        "edited": bool(post.get("updated_at")),
        "link": f"rants/{post['id']}/{post.get('slug') or ''}",
        "rt": 1,
        "rc": 0,
        "user_id": int(author.get("id") or 0),
        "user_username": username,
        "user_score": int(user_scores.get(post["user_uid"], 0)),
        "user_avatar": avatar_payload(avatar_seed(author)),
        "user_avatar_lg": avatar_payload(avatar_seed(author)),
        "editable": bool(viewer and viewer.get("uid") == post["user_uid"]),
        "project_uid": post.get("project_uid"),
        "project": project,
    }


def serialize_comment(
    comment: dict,
    rant_id: int,
    *,
    authors: dict,
    user_scores: dict,
    my_votes: dict,
    score_map: dict,
) -> dict:
    author = authors.get(comment["user_uid"]) or {}
    uid = comment["uid"]
    username = author.get("username") or ""
    return {
        "id": int(comment["id"]),
        "rant_id": int(rant_id),
        "body": comment.get("content") or "",
        "score": int(score_map.get(uid, 0)),
        "created_time": to_unix(comment.get("created_at")),
        "vote_state": int(my_votes.get(uid, 0)),
        "user_id": int(author.get("id") or 0),
        "user_username": username,
        "user_score": int(user_scores.get(comment["user_uid"], 0)),
        "user_avatar": avatar_payload(avatar_seed(author)),
    }
