#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements.  See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership.  The ASF licenses this file
# to you 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.
#

# This HTTP/2 server can be configured via the following environment variables:
# - SERVER_LISTEN_PORT: the port the server will listen on
# - SERVER_TLS: if 'yes' use TLS
# - SERVER_CA_CERT: TLS configuration
# - SERVER_CERTIFICATE: TLS configuration
# - SERVER_PRIVATE_KEY: TLS configuration
# - QUART_*: Quart configuration

import json
import os
import system_test

from hypercorn import Config as HConfig
from quart import Quart, request  # type: ignore[attr-defined]
try:
    from quart.static import send_file  # type: ignore[attr-defined]
except ImportError:
    from quart.helpers import send_file  # type: ignore[attr-defined, no-redef]  # mypy#1153

try:
    from quart.exceptions import HTTPStatusException  # type: ignore[attr-defined]
except ImportError:
    from werkzeug.exceptions import InternalServerError as HTTPStatusException  # type: ignore[no-redef]  # mypy#1153

# Hypercorn default config sets a connection idle timeout to 5 seconds. This
# will cause the connection to the server to occasionally drop when running on
# slower systems. We do not need idle connection timeout for CI - disable it.
#
HConfig.keep_alive_timeout = 50000.0

app = Quart(__name__)


class MyInfo:
    def __init__(self, fname, lname, id=None):
        self.fname = fname
        self.lname = lname
        self.id = id


my_info = MyInfo(fname="John", lname="Doe")


def image_file(name):
    return os.path.join(system_test.DIR, 'images', name)


@app.route("/myinfo/delete/<id>", methods=["DELETE"])
async def delete_myinfo(id):  # noqa
    my_info.id = id
    jsonStr = json.dumps(my_info.__dict__)
    return jsonStr


@app.route('/myinfo', methods=['GET', 'POST', 'PUT'])
async def create_myinfo():
    form = await request.form
    fname = form['fname']
    lname = form['lname']
    message = "Success! Your first name is %s, last name is %s" % (fname, lname)
    return message


def large_string(length):
    i = 0
    ret_string = ""
    while i < length:
        ret_string += str(i) + ","
        i += 1
    return ret_string


@app.route('/')
async def index():
    return large_string(1000)


@app.route('/largeget', methods=['GET'])
async def largeget():
    return large_string(50000)


@app.route('/patch', methods=['PATCH'])
async def patch():
    data = await request.data
    return data

# Return a 500 error, "Service Unavailable"


@app.route('/test/500')
async def METHOD_NAME():
    raise HTTPStatusException()


@app.route('/images/balanced-routing.png', methods=['GET'])
async def get_png_images():
    img_file = image_file("balanced-routing.png")
    return await send_file(img_file, mimetype='image/png')


@app.route('/images/apache.jpg', methods=['GET'])
async def get_jpg_images():
    img_file = image_file("apache.jpg")
    return await send_file(img_file, mimetype='image/jpg')


@app.route('/upload', methods=['POST'])
async def process_upload_data():
    for name, file in (await request.files).items():
        print(f'Processing {name}: {len(file.read())}')
    return "Success!"


def main():
    port = os.getenv('SERVER_LISTEN_PORT')
    if port is None:
        raise RuntimeError("Environment variable `SERVER_LISTEN_PORT` is not set.")
    if os.getenv('SERVER_TLS') == "yes":
        app.run(port=port,
                certfile=os.getenv('SERVER_CERTIFICATE'),
                keyfile=os.getenv('SERVER_PRIVATE_KEY'),
                ca_certs=os.getenv('SERVER_CA_CERT'))
    else:
        app.run(port=port)


if __name__ == '__main__':
    main()