"""
Cloud Pub/Sub API emulator.

Handles topics and subscriptions for Terraform's google_pubsub_topic
and google_pubsub_subscription resources.
"""

from flask import Blueprint, jsonify, request as flask_request

from gcplocal.services.base import GCPService
from gcplocal.constants import PUBSUB_API_PREFIX
from gcplocal.utils import error_response, timestamp_now

SVC = "pubsub"


class PubSubService(GCPService):
    service_name = "pubsub"
    api_prefix = PUBSUB_API_PREFIX

    def register_routes(self, bp: Blueprint) -> None:
        p = self.api_prefix

        # --- Topics ---
        bp.add_url_rule(
            f"{p}/projects/<project>/topics",
            "list_topics", self.list_topics, methods=["GET"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/topics/<topic>",
            "create_or_get_topic", self.create_or_get_topic, methods=["PUT", "GET"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/topics/<topic>",
            "patch_topic", self.patch_topic, methods=["PATCH"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/topics/<topic>",
            "delete_topic", self.delete_topic, methods=["DELETE"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/topics/<topic>:getIamPolicy",
            "get_topic_iam_policy", self.get_topic_iam_policy, methods=["GET"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/topics/<topic>:setIamPolicy",
            "set_topic_iam_policy", self.set_topic_iam_policy, methods=["POST"],
        )

        # --- Subscriptions ---
        bp.add_url_rule(
            f"{p}/projects/<project>/subscriptions",
            "list_subscriptions", self.list_subscriptions, methods=["GET"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/subscriptions/<sub>",
            "create_or_get_sub", self.create_or_get_sub, methods=["PUT", "GET"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/subscriptions/<sub>",
            "patch_subscription", self.patch_subscription, methods=["PATCH"],
        )
        bp.add_url_rule(
            f"{p}/projects/<project>/subscriptions/<sub>",
            "delete_subscription", self.delete_subscription, methods=["DELETE"],
        )

    # ── Topics ─────────────────────────────────────────────────────────

    def list_topics(self, project: str):
        topics = self.state.list(SVC, project, "topics")
        return jsonify({"topics": topics})

    def create_or_get_topic(self, project: str, topic: str):
        if flask_request.method == "GET":
            t = self.state.get(SVC, project, "topics", topic)
            if not t:
                return error_response(404, f"Topic projects/{project}/topics/{topic} not found")
            return jsonify(t)

        body = flask_request.get_json(silent=True) or {}
        t = {
            "name": f"projects/{project}/topics/{topic}",
            "labels": body.get("labels", {}),
            "messageStoragePolicy": body.get("messageStoragePolicy", {}),
            "kmsKeyName": body.get("kmsKeyName", ""),
            "schemaSettings": body.get("schemaSettings", {}),
            "messageRetentionDuration": body.get("messageRetentionDuration", ""),
        }
        self.state.put(SVC, project, "topics", topic, t)
        return jsonify(t)

    def patch_topic(self, project: str, topic: str):
        existing = self.state.get(SVC, project, "topics", topic)
        if not existing:
            return error_response(404, f"Topic not found")
        body = flask_request.get_json(silent=True) or {}
        topic_data = body.get("topic", body)
        mask = body.get("updateMask", "")
        if mask:
            for field in mask.split(","):
                field = field.strip()
                if field in topic_data:
                    existing[field] = topic_data[field]
        else:
            existing.update({k: v for k, v in topic_data.items() if k != "name"})
        self.state.put(SVC, project, "topics", topic, existing)
        return jsonify(existing)

    def delete_topic(self, project: str, topic: str):
        self.state.delete(SVC, project, "topics", topic)
        return "", 200

    def get_topic_iam_policy(self, project: str, topic: str):
        policy = self.state.get(SVC, project, f"topic_iam/{topic}", "policy")
        if not policy:
            policy = {"version": 1, "etag": "ACAB", "bindings": []}
        return jsonify(policy)

    def set_topic_iam_policy(self, project: str, topic: str):
        body = flask_request.get_json(silent=True) or {}
        policy = body.get("policy", {"version": 1, "etag": "ACAB", "bindings": []})
        self.state.put(SVC, project, f"topic_iam/{topic}", "policy", policy)
        return jsonify(policy)

    # ── Subscriptions ──────────────────────────────────────────────────

    def list_subscriptions(self, project: str):
        subs = self.state.list(SVC, project, "subscriptions")
        return jsonify({"subscriptions": subs})

    def create_or_get_sub(self, project: str, sub: str):
        if flask_request.method == "GET":
            s = self.state.get(SVC, project, "subscriptions", sub)
            if not s:
                return error_response(404, f"Subscription not found")
            return jsonify(s)

        body = flask_request.get_json(silent=True) or {}
        s = {
            "name": f"projects/{project}/subscriptions/{sub}",
            "topic": body.get("topic", ""),
            "ackDeadlineSeconds": body.get("ackDeadlineSeconds", 10),
            "messageRetentionDuration": body.get("messageRetentionDuration", "604800s"),
            "retainAckedMessages": body.get("retainAckedMessages", False),
            "pushConfig": body.get("pushConfig", {}),
            "expirationPolicy": body.get("expirationPolicy", {"ttl": "2678400s"}),
            "filter": body.get("filter", ""),
            "deadLetterPolicy": body.get("deadLetterPolicy", {}),
            "retryPolicy": body.get("retryPolicy", {}),
            "labels": body.get("labels", {}),
        }
        self.state.put(SVC, project, "subscriptions", sub, s)
        return jsonify(s)

    def patch_subscription(self, project: str, sub: str):
        existing = self.state.get(SVC, project, "subscriptions", sub)
        if not existing:
            return error_response(404, f"Subscription not found")
        body = flask_request.get_json(silent=True) or {}
        sub_data = body.get("subscription", body)
        mask = body.get("updateMask", "")
        if mask:
            for field in mask.split(","):
                field = field.strip()
                if field in sub_data:
                    existing[field] = sub_data[field]
        else:
            existing.update({k: v for k, v in sub_data.items() if k != "name"})
        self.state.put(SVC, project, "subscriptions", sub, existing)
        return jsonify(existing)

    def delete_subscription(self, project: str, sub: str):
        self.state.delete(SVC, project, "subscriptions", sub)
        return "", 200
