"""Save rd_oauth.py beside this file. Requires Python 3.11+."""

import os
import time
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlsplit
from rd_oauth import begin_link, finish_link, read_profile, revoke


class Callback(BaseHTTPRequestHandler):
    def log_message(self, *_args):
        pass  # The callback URL contains an authorization code.

    def do_GET(self):
        if urlsplit(self.path).path != "/callback":
            self.reply(404, "Not found")
            return
        if self.server.completed:
            self.reply(400, "This connection attempt has already finished")
            return
        self.server.completed = True
        transaction = self.server.transaction
        self.server.transaction = None
        try:
            callback = self.server.config["redirect_uri"] + "?" + urlsplit(self.path).query
            tokens = finish_link(self.server.config, callback, transaction)
            try:
                read_profile(self.server.config, tokens)
            finally:
                revoke(self.server.config, tokens["access_token"])
            self.reply(200, "Profile request succeeded. You can close this window.")
        except Exception:
            self.reply(400, "Connection failed. Start again.")

    def reply(self, status, message):
        self.send_response(status)
        self.send_header("Content-Type", "text/plain; charset=utf-8")
        self.send_header("Cache-Control", "no-store")
        self.send_header("Referrer-Policy", "no-referrer")
        self.end_headers()
        self.wfile.write(message.encode("utf-8"))


if __name__ == "__main__":
    # Bind only the loopback interface; let the OS choose an unused port.
    with HTTPServer(("127.0.0.1", 0), Callback) as server:
        server.timeout = 1
        server.completed = False
        server.config = {
            "issuer": os.environ["RD_ISSUER"],
            "client_id": os.environ["RD_CLIENT_ID"],
            "redirect_uri": f"http://127.0.0.1:{server.server_port}/callback",
        }
        url, server.transaction = begin_link(server.config)
        if not webbrowser.open(url):
            raise RuntimeError("Could not open the system browser")
        deadline = time.monotonic() + 600
        while not server.completed and time.monotonic() < deadline:
            server.handle_request()
        if not server.completed:
            raise TimeoutError("Connection timed out. Start again.")
