import base64
import hashlib
import http.server
import json
import os
import socketserver
import webbrowser
from urllib.parse import urlparse, parse_qs

import requests

BASE_URL = os.getenv('BASE_URL')
CLIENT_ID = os.getenv('CLIENT_ID')

AUTHORIZATION_SERVER_URL = BASE_URL + "/auth/v1/oauth2/authorize"
TOKEN_ENDPOINT_URL = BASE_URL + "/auth/v1/oauth2/token"
REDIRECT_URI = "http://localhost:8000"
SCOPE = "read write"

# Global variable to store the authorization code
authorization_code = None

class CallbackHandler(http.server.SimpleHTTPRequestHandler):
    def do_GET(self):
        global authorization_code
        # Parse the query parameters to extract the authorization code
        parsed_url = urlparse(self.path)
        query_params = parse_qs(parsed_url.query)
        authorization_code = query_params["code"][0]
        # Serve a simple HTML page to the user indicating that they can close the browser window
        self.send_response(200)
        self.send_header("Content-type", "text/html")
        self.end_headers()
        self.wfile.write(b"<html><body>You may now close this window.<script>setTimeout(function(){window.close();}, 1000);</script></body></html>")

# Function to request authorization code from the authorization server
def get_authorization_code():
    # Generate a random code verifier
    code_verifier = base64.urlsafe_b64encode(os.urandom(32)).decode("utf-8")

    # Calculate the code challenge from the code verifier
    code_challenge = base64.urlsafe_b64encode(hashlib.sha256(code_verifier.encode("utf-8")).digest()).decode("utf-8").rstrip("=")

    # Open a web browser with the authorization server's URL and client credentials
    auth_url = f"{AUTHORIZATION_SERVER_URL}?response_type=code&client_id={CLIENT_ID}&redirect_uri={REDIRECT_URI}&scope={SCOPE}&code_challenge={code_challenge}&code_challenge_method=S256"
    webbrowser.open(auth_url)

    return code_verifier

# Function to exchange the authorization code for an access token
def get_tokens(code_verifier):
    # Send a POST request to the authorization server's token endpoint with the client credentials and authorization code
    data = {
        "grant_type": "authorization_code",
        "client_id": CLIENT_ID,
        "redirect_uri": REDIRECT_URI,
        "code": authorization_code,
        "code_verifier": code_verifier,
    }
    response = requests.post(TOKEN_ENDPOINT_URL, data=data)
    response_json = response.json()
    print("Token Response: " + json.dumps(response_json, indent=2))
    return response_json


class TokenResponse:
    def __init__(self, json_data):
        self.access_token = json_data['access_token']
        self.expires_in = json_data['expires_in']
        self.token_type = json_data['token_type']
        self.refresh_token = json_data['refresh_token']
        self.refresh_token_generation = json_data['refresh_token_generation']
        user_data = json_data['user']
        self.user = User(user_data)

class User:
    def __init__(self, user_data):
        self.subject = user_data['subject']
        self.email = user_data['email']
        self.family_name = user_data['family_name']
        self.given_name = user_data['given_name']
        self.name = user_data['name']

def authorization_code_flow() -> TokenResponse:
    # Start the HTTP server before requesting the authorization code from the authorization server
    with socketserver.TCPServer(("localhost", 8000), CallbackHandler) as httpd:
        code_verifier = get_authorization_code()
        # Wait for the user to close the browser window and the authorization code to be extracted
        while not authorization_code:
            httpd.handle_request()
        token_response_json = get_tokens(code_verifier)
        return TokenResponse(token_response_json)

def refresh_access_token(refresh_token):
    # Send a POST request to the authorization server's token endpoint with the client credentials and refresh token
    data = {
        "grant_type": "refresh_token",
        "client_id": CLIENT_ID,
        "redirect_uri": REDIRECT_URI,
        "refresh_token": refresh_token,
    }
    response = requests.post(TOKEN_ENDPOINT_URL, data=data)
    # Check if the request was successful
    if response.status_code == 200:
        response_json = response.json()
        return TokenResponse(response_json)
    else:
        print(f"Error refreshing access token: {response.status_code}")


