# Copyright 2016 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Testable usage examples for Google Cloud Pubsub API wrapper

Each example function takes a ``client`` argument (which must be an instance
of :class:`google.cloud.pubsub.client.Client`) and uses it to perform a task
with the API.

To facilitate running the examples as system tests, each example is also passed
a ``to_delete`` list;  the function adds to the list any objects created which
need to be deleted during teardown.
"""

import time

from google.cloud.pubsub.client import Client


def snippet(func):
    """Mark ``func`` as a snippet example function."""
    func._snippet = True
    return func


def _millis():
    return time.time() * 1000


@snippet
def client_list_topics(client, to_delete):  # pylint: disable=unused-argument
    """List topics for a project."""

    def do_something_with(sub):  # pylint: disable=unused-argument
        pass

    # [START client_list_topics]
    for topic in client.list_topics():   # API request(s)
        do_something_with(topic)
    # [END client_list_topics]


@snippet
def client_list_subscriptions(client,
                              to_delete):  # pylint: disable=unused-argument
    """List all subscriptions for a project."""

    def do_something_with(sub):  # pylint: disable=unused-argument
        pass

    # [START client_list_subscriptions]
    for subscription in client.list_subscriptions():  # API request(s)
        do_something_with(subscription)
    # [END client_list_subscriptions]


@snippet
def client_topic(client, to_delete):  # pylint: disable=unused-argument
    """Topic factory."""
    TOPIC_NAME = 'topic_factory-%d' % (_millis(),)

    # [START client_topic]
    topic = client.topic(TOPIC_NAME)
    # [END client_topic]


@snippet
def client_subscription(client, to_delete):  # pylint: disable=unused-argument
    """Subscription factory."""
    SUBSCRIPTION_NAME = 'subscription_factory-%d' % (_millis(),)

    # [START client_subscription]
    subscription = client.subscription(
        SUBSCRIPTION_NAME, ack_deadline=60,
        retain_acked_messages=True)
    # [END client_subscription]


@snippet
def topic_create(client, to_delete):
    """Create a topic."""
    TOPIC_NAME = 'topic_create-%d' % (_millis(),)

    # [START topic_create]
    topic = client.topic(TOPIC_NAME)
    topic.create()              # API request
    # [END topic_create]

    to_delete.append(topic)


@snippet
def topic_exists(client, to_delete):
    """Test existence of a topic."""
    TOPIC_NAME = 'topic_exists-%d' % (_millis(),)
    topic = client.topic(TOPIC_NAME)
    to_delete.append(topic)

    # [START topic_exists]
    assert not topic.exists()   # API request
    topic.create()              # API request
    assert topic.exists()       # API request
    # [END topic_exists]


@snippet
def topic_delete(client, to_delete):  # pylint: disable=unused-argument
    """Delete a topic."""
    TOPIC_NAME = 'topic_delete-%d' % (_millis(),)
    topic = client.topic(TOPIC_NAME)
    topic.create()              # API request

    # [START topic_delete]
    assert topic.exists()       # API request
    topic.delete()
    assert not topic.exists()   # API request
    # [END topic_delete]


@snippet
def topic_iam_policy(client, to_delete):
    """Fetch / set a topic's IAM policy."""
    TOPIC_NAME = 'topic_iam_policy-%d' % (_millis(),)
    topic = client.topic(TOPIC_NAME)
    topic.create()
    to_delete.append(topic)

    # [START topic_get_iam_policy]
    policy = topic.get_iam_policy()             # API request
    # [END topic_get_iam_policy]

    assert len(policy.viewers) == 0
    assert len(policy.editors) == 0
    assert len(policy.owners) == 0

    # [START topic_set_iam_policy]
    ALL_USERS = policy.all_users()
    policy.viewers = [ALL_USERS]
    LOGS_GROUP = policy.group('cloud-logs@google.com')
    policy.editors = [LOGS_GROUP]
    new_policy = topic.set_iam_policy(policy)   # API request
    # [END topic_set_iam_policy]

    assert ALL_USERS in new_policy.viewers
    assert LOGS_GROUP in new_policy.editors


# @snippet   # Disabled due to #1687
def topic_check_iam_permissions(client, to_delete):
    """Check topic IAM permissions."""
    TOPIC_NAME = 'topic_check_iam_permissions-%d' % (_millis(),)
    topic = client.topic(TOPIC_NAME)
    topic.create()
    to_delete.append(topic)

    # [START topic_check_iam_permissions]
    from google.cloud.pubsub.iam import OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE
    TO_CHECK = [OWNER_ROLE, EDITOR_ROLE, VIEWER_ROLE]
    ALLOWED = topic.check_iam_permissions(TO_CHECK)
    assert set(ALLOWED) == set(TO_CHECK)
    # [END topic_check_iam_permissions]


@snippet
def topic_publish_messages(client, to_delete):
    """Publish messages to a topic."""
    TOPIC_NAME = 'topic_publish_messages-%d' % (_millis(),)
    topic = client.topic(TOPIC_NAME)
    topic.create()
    to_delete.append(topic)

    # [START topic_publish_simple_message]
    topic.publish(b'This is the message payload')               # API request
    # [END topic_publish_simple_message]

    # [START topic_publish_message_with_attrs]
    topic.publish(b'Another message payload', extra='EXTRA')    # API request
    # [END topic_publish_message_with_attrs]


@snippet
def topic_subscription(client, to_delete):
    """Create subscriptions to a topic."""
    TOPIC_NAME = 'topic_subscription-%d' % (_millis(),)
    SUB_DEFAULTS = 'topic_subscription-defaults-%d' % (_millis(),)
    SUB_ACK90 = 'topic_subscription-ack90-%d' % (_millis(),)
    topic = client.topic(TOPIC_NAME)
    topic.create()
    to_delete.append(topic)

    # [START topic_subscription_defaults]
    sub_defaults = topic.subscription(SUB_DEFAULTS)
    # [END topic_subscription_defaults]

    sub_defaults.create()                               # API request
    to_delete.append(sub_defaults)
    expected_names = set()
    expected_names.add(sub_defaults.full_name)

    # [START topic_subscription_ack90]
    sub_ack90 = topic.subscription(SUB_ACK90, ack_deadline=90)