from __future__ import annotations

import uuid
from typing import TYPE_CHECKING, Optional

if TYPE_CHECKING:
    from mockmesh.storage.manager import StorageManager


def handle_pubsub(
    sm: "StorageManager",
    project: str,
    resource: str,
    operation: str,
    body: dict,
    tpl: dict,
) -> Optional[dict]:
    # ── Topics ────────────────────────────────────────────────────────
    if resource == "topics":
        topic_name = body.get("_name", "mock-topic")
        q_key      = f"pubsub_topic_{project}_{topic_name}"

        if operation == "create":
            sm.nosql.put(q_key, "meta",
                         {"name": f"projects/{project}/topics/{topic_name}"})
            resp = dict(tpl.get("topics_create", {}))
            resp["name"] = f"projects/{project}/topics/{topic_name}"
            return resp

        if operation == "get":
            resp = dict(tpl.get("topics_get", {}))
            resp["name"] = f"projects/{project}/topics/{topic_name}"
            return resp

        if operation == "delete":
            return {}

        if operation == "publish":
            msg_ids = []
            for msg in body.get("messages", []):
                mid = str(uuid.uuid4())
                sm.nosql.put(q_key, mid, {
                    "MessageId": mid,
                    "data":      msg.get("data", ""),
                    "attributes": msg.get("attributes", {}),
                    "status":    "queued",
                })
                msg_ids.append(mid)
            resp = dict(tpl.get("topics_publish", {}))
            resp["messageIds"] = msg_ids
            return resp

        if operation == "list":
            return dict(tpl.get("topics_list", {"topics": []}))

    # ── Subscriptions ─────────────────────────────────────────────────
    if resource == "subscriptions":
        sub_name = body.get("_name", "mock-sub")
        topic    = body.get("topic", "")
        q_key    = f"pubsub_sub_{project}_{sub_name}"

        if operation == "create":
            sm.nosql.put(q_key, "meta", {
                "name":  f"projects/{project}/subscriptions/{sub_name}",
                "topic": topic,
            })
            resp = dict(tpl.get("subscriptions_create", {}))
            resp["name"]  = f"projects/{project}/subscriptions/{sub_name}"
            resp["topic"] = topic
            return resp

        if operation == "get":
            resp = dict(tpl.get("subscriptions_get", {}))
            resp["name"] = f"projects/{project}/subscriptions/{sub_name}"
            return resp

        if operation == "delete":
            return {}

        if operation == "pull":
            max_msgs = body.get("maxMessages", 1)
            # Pull from the matching topic queue.
            # The subscription record stores the topic name; we derive the
            # topic queue key from it so messages published to the topic are
            # visible to subscribers.
            sub_meta = sm.nosql.get(q_key, "meta") or {}
            topic_full = sub_meta.get("topic", "")
            # topic full name: projects/{p}/topics/{name}
            topic_name = topic_full.rsplit("/", 1)[-1] if "/" in topic_full else topic_full
            # Fall back to same-name topic if no meta
            if not topic_name:
                topic_name = sub_name
            topic_key = f"pubsub_topic_{project}_{topic_name}"
            records   = sm.nosql.query(topic_key, status="queued")
            received  = []
            for rec in records[:max_msgs]:
                sm.nosql.put(topic_key, rec["key"],
                             {**rec["value"], "status": "locked"})
                data = rec["value"].get("data", "")
                received.append({
                    "ackId":   str(uuid.uuid4()),
                    "message": {
                        "messageId": rec["key"],
                        "data":      data,
                        "publishTime": "2024-01-01T00:00:00.000Z",
                    },
                })
            resp = dict(tpl.get("subscriptions_pull", {"receivedMessages": []}))
            resp["receivedMessages"] = received
            return resp

        if operation == "acknowledge":
            return {}

        if operation == "list":
            return dict(tpl.get("subscriptions_list", {"subscriptions": []}))

    return None
