"""Blog app data endpoints.

Exposes read-only JSON queries at ``/internal/data/<query_name>`` for
cross-app callers via the internal data client.
"""
from __future__ import annotations

from quart import Blueprint, g, jsonify, request

from shared.infrastructure.data_client import DATA_HEADER
from shared.contracts.dtos import dto_to_dict
from services import blog_service


def register() -> Blueprint:
    bp = Blueprint("data", __name__, url_prefix="/internal/data")

    @bp.before_request
    async def _require_data_header():
        if not request.headers.get(DATA_HEADER):
            return jsonify({"error": "forbidden"}), 403
        from shared.infrastructure.internal_auth import validate_internal_request
        if not validate_internal_request():
            return jsonify({"error": "forbidden"}), 403

    _handlers: dict[str, object] = {}

    @bp.get("/<query_name>")
    async def handle_query(query_name: str):
        handler = _handlers.get(query_name)
        if handler is None:
            return jsonify({"error": "unknown query"}), 404
        result = await handler()
        return jsonify(result)

    # --- post-by-slug ---
    async def _post_by_slug():
        slug = request.args.get("slug", "")
        post = await blog_service.get_post_by_slug(g.s, slug)
        if not post:
            return None
        return dto_to_dict(post)

    _handlers["post-by-slug"] = _post_by_slug

    # --- post-by-id ---
    async def _post_by_id():
        post_id = int(request.args.get("id", 0))
        post = await blog_service.get_post_by_id(g.s, post_id)
        if not post:
            return None
        return dto_to_dict(post)

    _handlers["post-by-id"] = _post_by_id

    # --- posts-by-ids ---
    async def _posts_by_ids():
        ids_raw = request.args.get("ids", "")
        if not ids_raw:
            return []
        ids = [int(x.strip()) for x in ids_raw.split(",") if x.strip()]
        posts = await blog_service.get_posts_by_ids(g.s, ids)
        return [dto_to_dict(p) for p in posts]

    _handlers["posts-by-ids"] = _posts_by_ids

    # --- search-posts ---
    async def _search_posts():
        query = request.args.get("query", "")
        page = int(request.args.get("page", 1))
        per_page = int(request.args.get("per_page", 10))
        posts, total = await blog_service.search_posts(g.s, query, page, per_page)
        return {"posts": [dto_to_dict(p) for p in posts], "total": total}

    _handlers["search-posts"] = _search_posts

    # --- page-config-ensure ---
    async def _page_config_ensure():
        """Get or create a PageConfig for a container_type + container_id."""
        from sqlalchemy import select
        from shared.models.page_config import PageConfig

        container_type = request.args.get("container_type", "page")
        container_id = request.args.get("container_id", type=int)
        if container_id is None:
            return {"error": "container_id required"}, 400

        row = (await g.s.execute(
            select(PageConfig).where(
                PageConfig.container_type == container_type,
                PageConfig.container_id == container_id,
            )
        )).scalar_one_or_none()

        if row is None:
            row = PageConfig(
                container_type=container_type,
                container_id=container_id,
                features={},
            )
            g.s.add(row)
            await g.s.flush()

        return {
            "id": row.id,
            "container_type": row.container_type,
            "container_id": row.container_id,
        }

    _handlers["page-config-ensure"] = _page_config_ensure

    # --- page-config ---
    async def _page_config():
        """Return a single PageConfig by container_type + container_id."""
        from sqlalchemy import select
        from shared.models.page_config import PageConfig

        ct = request.args.get("container_type", "page")
        cid = request.args.get("container_id", type=int)
        if cid is None:
            return None
        pc = (await g.s.execute(
            select(PageConfig).where(
                PageConfig.container_type == ct,
                PageConfig.container_id == cid,
            )
        )).scalar_one_or_none()
        if not pc:
            return None
        return _page_config_dict(pc)

    _handlers["page-config"] = _page_config

    # --- page-config-by-id ---
    async def _page_config_by_id():
        """Return a single PageConfig by its primary key."""
        from shared.models.page_config import PageConfig

        pc_id = request.args.get("id", type=int)
        if pc_id is None:
            return None
        pc = await g.s.get(PageConfig, pc_id)
        if not pc:
            return None
        return _page_config_dict(pc)

    _handlers["page-config-by-id"] = _page_config_by_id

    # --- page-configs-batch ---
    async def _page_configs_batch():
        """Return PageConfigs for multiple container_ids (comma-separated)."""
        from sqlalchemy import select
        from shared.models.page_config import PageConfig

        ct = request.args.get("container_type", "page")
        ids_raw = request.args.get("ids", "")
        if not ids_raw:
            return []
        ids = [int(x.strip()) for x in ids_raw.split(",") if x.strip()]
        if not ids:
            return []
        result = await g.s.execute(
            select(PageConfig).where(
                PageConfig.container_type == ct,
                PageConfig.container_id.in_(ids),
            )
        )
        return [_page_config_dict(pc) for pc in result.scalars().all()]

    _handlers["page-configs-batch"] = _page_configs_batch

    return bp


def _page_config_dict(pc) -> dict:
    """Serialize PageConfig to a JSON-safe dict."""
    return {
        "id": pc.id,
        "container_type": pc.container_type,
        "container_id": pc.container_id,
        "features": pc.features or {},
        "sumup_merchant_code": pc.sumup_merchant_code,
        "sumup_api_key": pc.sumup_api_key,
        "sumup_checkout_prefix": pc.sumup_checkout_prefix,
    }
