#!/usr/bin/env python3
# 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.
"""ASF Infrastructure Reporting Dashboard"""
"""Handler for oauth operations"""

from ..lib import middleware
import quart
import aiohttp
import uuid
import urllib.parse
import time

OAUTH_URL_INIT = "https://oauth.apache.org/auth-oidc?state=%s&redirect_uri=%s"
OAUTH_URL_CALLBACK = "https://oauth.apache.org/token-oidc?code=%s"


async def process(form_data):
    if quart.request.method == "GET":
        code = form_data.get("code")
        state = form_data.get("state")
        if not code or not state:  # Presumably first step in OAuth
            state = str(uuid.uuid4())
            callback_url = urllib.parse.urljoin(
                quart.request.host_url.replace("http://", "https://"),
                f"/oauth?state={state}",
            )
            redirect_url = OAUTH_URL_INIT % (state, urllib.parse.quote(callback_url))
            headers = {
                "Location": redirect_url,
            }
            return quart.Response(status=302, response="Redirecting...", headers=headers)
        else:  # Callback from oauth.a.o
            ct = aiohttp.client.ClientTimeout(sock_read=15)
            async with aiohttp.client.ClientSession(timeout=ct) as session:
                rv = await session.get(OAUTH_URL_CALLBACK % code)
                assert rv.status == 200, "Could not verify oauth response."
                oauth_data = await rv.json()
                quart.session.clear()
                quart.session.update(oauth_data)
                # Quart sessions live for the entirety of the browser session. We don't want this to extend
                # too far into the future (abuse??), so let's set a fixed timeout after which a new login
                # will be required.
                quart.session["timestamp"] = int(time.time())
            uid = quart.session["uid"]
            return quart.Response(
                status=200,
                response=f"Successfully logged in! Welcome, {uid}\n",
            )


quart.current_app.add_url_rule(
    "/api/oauth",
    methods=[
        "GET",  # OAuth request
    ],
    view_func=middleware.glued(process),
)
