# retoor <retoor@molodetz.nl>
import logging
from datetime import datetime, timezone
from fastapi import APIRouter, Request
from fastapi.responses import RedirectResponse, JSONResponse, HTMLResponse
from devplacepy.database import get_table, db, paginate, resolve_object_url, _now_iso
from devplacepy.utils import generate_uid, require_user, time_ago, redirect_back
from devplacepy.seo import base_seo_context
from devplacepy.responses import respond
from devplacepy.schemas import SavedOut
from devplacepy.services.audit import record as audit

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

BOOKMARKABLE: set[str] = {"post", "gist", "project", "news", "quiz"}

TABLE_BY_TYPE: dict[str, str] = {
    "post": "posts",
    "gist": "gists",
    "project": "projects",
    "news": "news",
}

LABEL_BY_TYPE: dict[str, str] = {
    "post": "Post",
    "gist": "Gist",
    "project": "Project",
    "news": "Article",
}


@router.get("/saved", response_class=HTMLResponse)
async def saved_page(request: Request, before: str = None):
    user = require_user(request)
    bookmarks = get_table("bookmarks")
    rows, next_cursor = paginate(bookmarks, before=before, user_uid=user["uid"])

    uids_by_type: dict[str, list] = {}
    for row in rows:
        uids_by_type.setdefault(row["target_type"], []).append(row["target_uid"])

    resolved: dict[tuple, dict] = {}
    for target_type, uids in uids_by_type.items():
        table_name = TABLE_BY_TYPE.get(target_type)
        if not table_name or table_name not in db.tables:
            continue
        table = get_table(table_name)
        clauses = [table.table.columns.uid.in_(uids)]
        if table.has_column("deleted_at"):
            clauses.append(table.table.columns.deleted_at.is_(None))
        for obj in table.find(*clauses):
            resolved[(target_type, obj["uid"])] = obj

    items = []
    for row in rows:
        obj = resolved.get((row["target_type"], row["target_uid"]))
        if not obj:
            continue
        title = obj.get("title") or (obj.get("content", "") or "")[:80] or "Untitled"
        items.append(
            {
                "target_type": row["target_type"],
                "type_label": LABEL_BY_TYPE.get(
                    row["target_type"], row["target_type"].title()
                ),
                "title": title,
                "url": resolve_object_url(row["target_type"], row["target_uid"]),
                "time_ago": time_ago(row["created_at"]),
            }
        )

    seo_ctx = base_seo_context(
        request,
        title="Saved",
        description="Your saved content on DevPlace.",
        robots="noindex,nofollow",
    )
    return respond(
        request,
        "saved.html",
        {
            **seo_ctx,
            "request": request,
            "user": user,
            "items": items,
            "next_cursor": next_cursor,
        },
        model=SavedOut,
    )


@router.post("/{target_type}/{target_uid}")
async def toggle_bookmark(request: Request, target_type: str, target_uid: str):
    user = require_user(request)
    if target_type not in BOOKMARKABLE:
        return JSONResponse({"error": "Invalid target"}, status_code=400)

    bookmarks = get_table("bookmarks")
    existing = bookmarks.find_one(
        user_uid=user["uid"], target_uid=target_uid, target_type=target_type
    )
    if existing and not existing.get("deleted_at"):
        bookmarks.update(
            {"id": existing["id"], "deleted_at": _now_iso(), "deleted_by": user["uid"]},
            ["id"],
        )
        saved = False
    elif existing:
        bookmarks.update(
            {"id": existing["id"], "deleted_at": None, "deleted_by": None}, ["id"]
        )
        saved = True
    else:
        bookmarks.insert(
            {
                "uid": generate_uid(),
                "user_uid": user["uid"],
                "target_uid": target_uid,
                "target_type": target_type,
                "created_at": datetime.now(timezone.utc).isoformat(),
                "deleted_at": None,
                "deleted_by": None,
            }
        )
        saved = True

    audit.record(
        request,
        "bookmark.add" if saved else "bookmark.remove",
        user=user,
        target_type=target_type,
        target_uid=target_uid,
        summary=f"{user['username']} {'bookmarked' if saved else 'removed bookmark from'} {target_type} {target_uid}",
        links=[audit.target(target_type, target_uid)],
    )

    if request.headers.get("x-requested-with") == "fetch":
        return JSONResponse({"saved": saved})
    return RedirectResponse(url=redirect_back(request), status_code=302)
