"""Unified Knowledge endpoint — notes, tasks, plans, and processes in one queryable feed."""
import logging

from quart import Blueprint, jsonify, request

from scribe.auth import get_current_user_id, login_required
from scribe.routes.utils import parse_pagination
from scribe.services.access import label_shared_items

logger = logging.getLogger(__name__)

knowledge_bp = Blueprint("knowledge", __name__, url_prefix="/api/knowledge")

_VALID_TYPES = {"note", "task", "plan", "process"}
_VALID_SORTS = {"modified", "created", "alpha", "type"}


@knowledge_bp.route("", methods=["GET"])
@login_required
async def list_knowledge():
    """Return paginated knowledge objects with optional filtering.

    Query params:
      type        — one of note|task|plan|process (omit for all)
      tags        — comma-separated tag filter (AND logic)
      sort        — modified|created|alpha|type (default: modified)
      q           — search query (semantic when provided, keyword fallback)
      page        — 1-based page number (default 1)
      per_page    — items per page (default 24, max 100)
    """
    uid = get_current_user_id()
    note_type = request.args.get("type", "").strip().lower() or None
    tags_raw = request.args.get("tags", "").strip()
    tags = [t.strip() for t in tags_raw.split(",") if t.strip()] if tags_raw else []
    sort = request.args.get("sort", "modified").strip().lower()
    q = request.args.get("q", "").strip() or None

    if note_type and note_type not in _VALID_TYPES:
        return jsonify({"error": f"Invalid type. Must be one of: {', '.join(sorted(_VALID_TYPES))}"}), 400
    if sort not in _VALID_SORTS:
        sort = "modified"

    limit, offset = parse_pagination(default_limit=24, max_limit=100)
    page = max(1, int(request.args.get("page", 1)))

    from scribe.services.knowledge import query_knowledge
    items, total = await query_knowledge(
        user_id=uid,
        note_type=note_type,
        tags=tags,
        sort=sort,
        q=q,
        limit=limit,
        offset=offset,
    )

    return jsonify({
        # Mark rows another user owns: this feed can be mixed-ownership, and an
        # unmarked card reads as one the viewer wrote.
        "items": await label_shared_items(uid, items),
        "total": total,
        "page": page,
        "per_page": limit,
        "pages": max(1, (total + limit - 1) // limit),
    })


@knowledge_bp.route("/ids", methods=["GET"])
@login_required
async def list_knowledge_ids():
    """Return note IDs only (cheap) for the two-tier pagination feed.

    Same filter params as GET /api/knowledge.
    Additional params: limit (default 100, max 200), offset (default 0).
    Returns {ids, total, has_more}.
    """
    uid = get_current_user_id()
    note_type = request.args.get("type", "").strip().lower() or None
    tags_raw = request.args.get("tags", "").strip()
    tags = [t.strip() for t in tags_raw.split(",") if t.strip()] if tags_raw else []
    sort = request.args.get("sort", "modified").strip().lower()
    q = request.args.get("q", "").strip() or None
    if sort not in _VALID_SORTS:
        sort = "modified"
    try:
        limit = min(int(request.args.get("limit", 100)), 200)
        offset = max(0, int(request.args.get("offset", 0)))
    except ValueError:
        return jsonify({"error": "Invalid limit or offset"}), 400

    if note_type and note_type not in _VALID_TYPES:
        return jsonify({"error": "Invalid type"}), 400

    from scribe.services.knowledge import query_knowledge_ids
    ids, total = await query_knowledge_ids(
        user_id=uid, note_type=note_type, tags=tags,
        sort=sort, q=q, limit=limit, offset=offset,
    )
    return jsonify({"ids": ids, "total": total, "has_more": (offset + len(ids)) < total})


@knowledge_bp.route("/batch", methods=["GET"])
@login_required
async def get_knowledge_batch():
    """Fetch full items for a comma-separated list of IDs (max 100).

    Returns {items: [...]} in the order of the requested IDs.
    """
    uid = get_current_user_id()
    ids_raw = request.args.get("ids", "").strip()
    if not ids_raw:
        return jsonify({"items": []})
    try:
        ids = [int(x) for x in ids_raw.split(",") if x.strip()]
    except ValueError:
        return jsonify({"error": "Invalid IDs"}), 400
    if len(ids) > 100:
        return jsonify({"error": "Too many IDs (max 100)"}), 400

    from scribe.services.knowledge import get_knowledge_by_ids
    items = await get_knowledge_by_ids(uid, ids)
    # The scrolling feed hydrates its cards here, not from the list route, so the
    # ownership markers have to be applied on this path too.
    return jsonify({"items": await label_shared_items(uid, items)})


@knowledge_bp.route("/tags", methods=["GET"])
@login_required
async def list_knowledge_tags():
    """Return all tags used across knowledge objects (excludes tasks)."""
    uid = get_current_user_id()
    note_type = request.args.get("type", "").strip().lower() or None

    from scribe.services.knowledge import get_knowledge_tags
    tags = await get_knowledge_tags(uid, note_type=note_type)
    return jsonify({"tags": tags})


@knowledge_bp.route("/counts", methods=["GET"])
@login_required
async def get_knowledge_counts():
    """Return per-type counts — used by the sidebar to show item counts."""
    uid = get_current_user_id()
    tags_raw = request.args.get("tags", "").strip()
    tags = [t.strip() for t in tags_raw.split(",") if t.strip()] if tags_raw else None

    from scribe.services.knowledge import get_knowledge_counts as _counts
    counts = await _counts(uid, tags=tags)
    return jsonify(counts)
