# retoor <retoor@molodetz.nl>

import logging
from datetime import datetime, timezone

from fastapi import APIRouter, Request

from devplacepy.database import (
    get_table,
    get_users_by_uids,
    get_user_votes,
    get_vote_counts,
    get_user_stars,
)
from devplacepy.content import apply_vote, delete_comment_record, is_owner, is_admin
from devplacepy.services.audit import record as audit
from devplacepy.services.correction import schedule_correction
from devplacepy.services.ai_modifier import schedule_modification
from devplacepy.services.devrant.params import merge_params
from devplacepy.services.devrant.ids import as_int, comment_by_id
from devplacepy.services.devrant.serializers import serialize_comment
from devplacepy.routers.devrant._shared import dr_ok, dr_error, resolve_actor, unauthorized

logger = logging.getLogger(__name__)
router = APIRouter()


def _rant_id_for(comment: dict) -> int:
    post = get_table("posts").find_one(uid=comment.get("target_uid"))
    return int(post["id"]) if post else 0


def _serialize_single(comment: dict, viewer) -> dict:
    authors = get_users_by_uids([comment["user_uid"]])
    user_scores = {comment["user_uid"]: get_user_stars(comment["user_uid"])}
    ups, downs = get_vote_counts([comment["uid"]])
    score_map = {comment["uid"]: ups.get(comment["uid"], 0) - downs.get(comment["uid"], 0)}
    my_votes = get_user_votes(viewer["uid"], [comment["uid"]]) if viewer else {}
    return serialize_comment(
        comment,
        _rant_id_for(comment),
        authors=authors,
        user_scores=user_scores,
        my_votes=my_votes,
        score_map=score_map,
    )


@router.get("/comments/{comment_id}")
async def get_comment(request: Request, comment_id: str):
    params = await merge_params(request)
    viewer = resolve_actor(request, params)
    comment = comment_by_id(comment_id)
    if not comment:
        return dr_error("Invalid comment specified in path.")
    return dr_ok(comment=_serialize_single(comment, viewer))


@router.post("/comments/{comment_id}")
async def edit_comment(request: Request, comment_id: str):
    params = await merge_params(request)
    user = resolve_actor(request, params)
    if not user:
        return unauthorized()
    comment = comment_by_id(comment_id)
    if not comment:
        return dr_error("Invalid comment specified in path.")
    if not is_owner(comment, user):
        return dr_error("You can only edit your own comments.", fail_reason="not_owner")
    text = (params.get("comment") or "").strip()
    if len(text) < 1 or len(text) > 1000:
        return dr_error("Invalid comment length.", fail_reason="length")
    get_table("comments").update(
        {
            "uid": comment["uid"],
            "content": text,
            "updated_at": datetime.now(timezone.utc).isoformat(),
        },
        ["uid"],
    )
    schedule_correction(user, "comments", comment["uid"], request)
    schedule_modification(user, "comments", comment["uid"], request)
    audit.record(
        request,
        "comment.edit",
        user=user,
        target_type="comment",
        target_uid=comment["uid"],
        origin="devrant",
        summary=f"{user['username']} edited comment {comment['id']}",
        links=[audit.target("comment", comment["uid"])],
    )
    return dr_ok()


@router.delete("/comments/{comment_id}")
async def delete_comment(request: Request, comment_id: str):
    params = await merge_params(request)
    user = resolve_actor(request, params)
    if not user:
        return unauthorized()
    comment = comment_by_id(comment_id)
    if not comment:
        return dr_error("Invalid comment specified in path.")
    if not (is_owner(comment, user) or is_admin(user)):
        return dr_error("You can only delete your own comments.")
    delete_comment_record(request, user, comment)
    return dr_ok()


@router.post("/comments/{comment_id}/vote")
async def vote_comment(request: Request, comment_id: str):
    params = await merge_params(request)
    user = resolve_actor(request, params)
    if not user:
        return unauthorized()
    comment = comment_by_id(comment_id)
    if not comment:
        return dr_error("Invalid comment specified in path.")
    value = as_int(params.get("vote"))
    if value not in (-1, 0, 1):
        return dr_error("Invalid vote.")
    apply_vote(request, user, "comment", comment["uid"], value)
    return dr_ok()
