"""Bookmark repository — typed CRUD for user event bookmarks."""
from __future__ import annotations

import logging
from typing import Any

from repo_core import BaseRepository
from repo_core.events.hooks import hook
from repo_core.domains.bookmark.model import Bookmark, BookmarkTargetType

logger = logging.getLogger(__name__)


class BookmarkRepository(BaseRepository[Bookmark]):
    """Repository for persisting and querying user bookmarks.

    Usage::

        repo = BookmarkRepository(model=Bookmark)
        async with repo:
            bm = await repo.save_bookmark(user_id=42, event_id="123")
            assert await repo.is_bookmarked(42, "123") is True
            await repo.remove_bookmark(user_id=42, event_id="123")
    """

    TABLE = "bookmarks"

    @hook("after_create")
    async def _log_created(self, instance: Bookmark) -> None:
        logger.info("Bookmark created: user_id=%s event=%s",
                     instance.user_id, instance.target_id)

    async def save_bookmark(self, *, user_id: int, event_id: str) -> Bookmark:
        """Bookmark an event — idempotent."""
        existing = await self.first(
            self.TABLE,
            {
                "user_id": user_id,
                "target_type": BookmarkTargetType.EVENT.value,
                "target_id": event_id,
            },
        )
        if existing is not None:
            return existing

        return await self.insert_one(
            self.TABLE,
            {
                "user_id": user_id,
                "target_type": BookmarkTargetType.EVENT.value,
                "target_id": event_id,
            },
            returning=["*"],
        )

    async def remove_bookmark(self, *, user_id: int, event_id: str) -> bool:
        """Remove a bookmark. Returns ``True`` if a row was deleted."""
        deleted = await self.remove(
            self.TABLE,
            {
                "user_id": user_id,
                "target_type": BookmarkTargetType.EVENT.value,
                "target_id": event_id,
            },
        )
        return deleted > 0

    async def is_bookmarked(self, user_id: int, event_id: str) -> bool:
        """Return ``True`` if *user_id* has bookmarked the given event."""
        row = await self.first(
            self.TABLE,
            {
                "user_id": user_id,
                "target_type": BookmarkTargetType.EVENT.value,
                "target_id": event_id,
            },
        )
        return row is not None

    async def list_bookmarks(
        self, user_id: int, *, limit: int | None = None, offset: int | None = None
    ) -> tuple[list[Bookmark], int]:
        """Return all bookmarks for a user, newest first, with total count."""
        total = await self.count(self.TABLE, {"user_id": user_id})
        rows = await self.find(
            self.TABLE, {"user_id": user_id},
            limit=limit, offset=offset, order_by=["-created_at"],
        )
        return rows, total
