# Copyright 2019 Google LLC
#
# 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.

# [START functions_helloworld_http]
# [START functions_http_content]

# [START functions_http_method]
# [START functions_helloworld_get]
import functions_framework

# [END functions_http_method]
# [END functions_helloworld_get]

from markupsafe import escape

# [END functions_helloworld_http]
# [END functions_http_content]


# [START functions_helloworld_get]
@functions_framework.http
def hello_get(request):
    """HTTP Cloud Function.
    Args:
        request (flask.Request): The request object.
        <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
    Note:
        For more information on how Flask integrates with Cloud
        Functions, see the `Writing HTTP functions` page.
        <https://cloud.google.com/functions/docs/writing/http#http_frameworks>
    """
    return "Hello World!"


# [END functions_helloworld_get]


# [START functions_helloworld_http]
@functions_framework.http
def hello_http(request):
    """HTTP Cloud Function.
    Args:
        request (flask.Request): The request object.
        <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
    """
    request_json = request.get_json(silent=True)
    request_args = request.args

    if request_json and "name" in request_json:
        name = request_json["name"]
    elif request_args and "name" in request_args:
        name = request_args["name"]
    else:
        name = "World"
    return f"Hello {escape(name)}!"


# [END functions_helloworld_http]


# [START functions_helloworld_pubsub]
def hello_pubsub(event, context):
    """Background Cloud Function to be triggered by Pub/Sub.
    Args:
         event (dict):  The dictionary with data specific to this type of
                        event. The `@type` field maps to
                         `type.googleapis.com/google.pubsub.v1.PubsubMessage`.
                        The `data` field maps to the PubsubMessage data
                        in a base64-encoded string. The `attributes` field maps
                        to the PubsubMessage attributes if any is present.
         context (google.cloud.functions.Context): Metadata of triggering event
                        including `event_id` which maps to the PubsubMessage
                        messageId, `timestamp` which maps to the PubsubMessage
                        publishTime, `event_type` which maps to
                        `google.pubsub.topic.publish`, and `resource` which is
                        a dictionary that describes the service API endpoint
                        pubsub.googleapis.com, the triggering topic's name, and
                        the triggering event type
                        `type.googleapis.com/google.pubsub.v1.PubsubMessage`.
    Returns:
        None. The output is written to Cloud Logging.
    """
    import base64

    print(
        """This Function was triggered by messageId {} published at {} to {}
    """.format(
            context.event_id, context.timestamp, context.resource["name"]
        )
    )

    if "data" in event:
        name = base64.b64decode(event["data"]).decode("utf-8")
    else:
        name = "World"
    print(f"Hello {name}!")


# [END functions_helloworld_pubsub]


# [START functions_helloworld_storage]
def hello_gcs(event, context):
    """Background Cloud Function to be triggered by Cloud Storage.
       This generic function logs relevant data when a file is changed,
       and works for all Cloud Storage CRUD operations.
    Args:
        event (dict):  The dictionary with data specific to this type of event.
                       The `data` field contains a description of the event in
                       the Cloud Storage `object` format described here:
                       https://cloud.google.com/storage/docs/json_api/v1/objects#resource
        context (google.cloud.functions.Context): Metadata of triggering event.
    Returns:
        None; the output is written to Cloud Logging
    """

    print(f"Event ID: {context.event_id}")
    print(f"Event type: {context.event_type}")
    print("Bucket: {}".format(event["bucket"]))
    print("File: {}".format(event["name"]))
    print("Metageneration: {}".format(event["metageneration"]))
    print("Created: {}".format(event["timeCreated"]))
    print("Updated: {}".format(event["updated"]))


# [END functions_helloworld_storage]


# [START functions_http_content]
@functions_framework.http
def hello_content(request):
    """Responds to an HTTP request using data from the request body parsed
    according to the "content-type" header.
    Args:
        request (flask.Request): The request object.
        <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
    """
    content_type = request.headers["content-type"]
    if content_type == "application/json":
        request_json = request.get_json(silent=True)
        if request_json and "name" in request_json:
            name = request_json["name"]
        else:
            raise ValueError("JSON is invalid, or missing a 'name' property")
    elif content_type == "application/octet-stream":
        name = request.data
    elif content_type == "text/plain":
        name = request.data
    elif content_type == "application/x-www-form-urlencoded":
        name = request.form.get("name")
    else:
        raise ValueError(f"Unknown content type: {content_type}")
    return f"Hello {escape(name)}!"


# [END functions_http_content]


# [START functions_http_method]
@functions_framework.http
def hello_method(request):
    """Responds to a GET request with "Hello world!". Forbids a PUT request.
    Args:
        request (flask.Request): The request object.
        <https://flask.palletsprojects.com/en/1.1.x/api/#incoming-request-data>
    Returns:
        The response text, or any set of values that can be turned into a
        Response object using `make_response`
        <https://flask.palletsprojects.com/en/1.1.x/api/#flask.make_response>.
    """
    from flask import abort

    if request.method == "GET":
        return "Hello World!"
    elif request.method == "PUT":
        return abort(403)
    else:
        return abort(405)


# [END functions_http_method]


# [START functions_helloworld_error]
@functions_framework.http
def hello_error_1(request):
    # This WILL be reported to Error Reporting,
    # and WILL NOT show up in logs or
    # terminate the function.
    from google.cloud import error_reporting

    client = error_reporting.Client()

    try:
        raise RuntimeError("I failed you")
    except RuntimeError:
        client.report_exception()

    # This WILL be reported to Error Reporting,
    # and WILL terminate the function
    raise RuntimeError("I failed you")


# [END functions_helloworld_error]


# [START functions_helloworld_error]
@functions_framework.http
def hello_error_2(request):
    # These errors WILL NOT be reported to Error
    # Reporting, but will show up in logs.
    import logging
    import sys

    print(RuntimeError("I failed you (print to stdout)"))
    logging.warning(RuntimeError("I failed you (logging.warning)"))
    logging.error(RuntimeError("I failed you (logging.error)"))
    sys.stderr.write("I failed you (sys.stderr.write)\n")

    # This is considered a successful execution and WILL NOT be reported
    # to Error Reporting, but the status code (500) WILL be logged.
    from flask import abort

    return abort(500)


# [END functions_helloworld_error]
