"""A simple server that obtains the code generated by Keycloak.

A url is presented to the user, they navigate to it in a browser and proceed with authentication.
Then keycloak will redirect the browser to this web server and we extract the code generated by keycloak.
"""

import sys
import urllib.parse
from http.server import BaseHTTPRequestHandler, HTTPServer


class OIDCResponseServer(BaseHTTPRequestHandler):
    """Server to receive oidc callback to enable code exchange with PKCE."""

    expected_path = ""
    expected_state = ""
    token_code = None

    def do_GET(self):
        """Handle get request from users browser."""
        # expected like http://127.0.0.1:8080/authorisation-code/callback?code=XXXX&state=YYYY
        try:
            if not self.path.startswith(f"{OIDCResponseServer.expected_path}?"):
                raise Exception(f"bad path '{self.path}' not start with '{self.expected_path}?'")
            parsed = urllib.parse.urlparse(self.path)
            qs = urllib.parse.parse_qs(parsed.query)
            if OIDCResponseServer.expected_state != qs["state"][0]:
                raise Exception("Returned state does not match")
            OIDCResponseServer.token_code = qs["code"][0]

        except Exception as e:
            self.send_response(400)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(bytes("<html><head><title>Azul Client Auth</title></head>", "utf-8"))
            self.wfile.write(bytes("<body>", "utf-8"))
            self.wfile.write(bytes("<p>Failure</p>", "utf-8"))
            self.wfile.write(bytes(f"<p>{str(e)}</p>", "utf-8"))
            self.wfile.write(bytes("</body></html>", "utf-8"))

        else:
            self.send_response(200)
            self.send_header("Content-type", "text/html")
            self.end_headers()
            self.wfile.write(bytes("<html><head><title>Azul Client Auth</title></head>", "utf-8"))
            self.wfile.write(bytes("<body>", "utf-8"))
            self.wfile.write(bytes("<p>Success</p>", "utf-8"))
            self.wfile.write(bytes("<p>You may now close this tab.</p>", "utf-8"))
            self.wfile.write(bytes("</body></html>", "utf-8"))


def receive_code(
    expected_state: str, *, path: str = "/authorisation-code/callback", hostname: str = "localhost", port: int = 8080
):
    """Receive one http request from users browser, parse code and shut down."""
    OIDCResponseServer.expected_path = path
    OIDCResponseServer.expected_state = expected_state
    server = HTTPServer((hostname, port), OIDCResponseServer)
    print("Server started at http://%s:%s. Waiting for oauth callback." % (hostname, port), file=sys.stderr)

    try:
        while not OIDCResponseServer.token_code:
            server.handle_request()
    except KeyboardInterrupt:
        pass
    server.server_close()
    print("Server stopped.")
    return OIDCResponseServer.token_code


if __name__ == "__main__":
    code = receive_code("51998", path="/test")
    print(f"{code=}")
