import base64

import requests
import webbrowser
from http.server import BaseHTTPRequestHandler, HTTPServer
import urllib.parse
import threading
import time
import os.path

client_id = '***REDACTED***'
client_secret = None
token = None


def resolve_client_secret():
    global client_secret
    if os.path.exists('secret'):
        with open('secret', 'r') as file:
            client_secret = file.readline().strip()
    else:
        client_secret = input("Enter the application secret: ")
        with open('secret', 'w') as file:
            file.write(client_secret)


def retrieve_web_api_token(authorization_code):
    global token

    token_url = 'https://accounts.spotify.com/api/token'

    token_data = {
        "grant_type": "authorization_code",
        "client_secret": client_secret,
        "client_id":     client_id,
        "code": authorization_code,
        'redirect_uri': 'http://localhost:8888',
    }

    print("\nAuthenticating WEB API\n")

    auth_string = f'{client_id}:{client_secret}'
    b64_auth_string = base64.b64encode(auth_string.encode()).decode()

    # Define the headers
    headers = {
        'Content-Type': 'application/x-www-form-urlencoded',
        'Authorization': f'Basic {b64_auth_string}'
    }

    token_response = requests.post(token_url, data=token_data, headers=headers)

    if token_response.status_code not in range(200, 299):
        print(f"Failed to retrieve access token: {token_response.status_code}")
        print(token_response.json())
        raise ValueError

    token = token_response.json()['access_token']


class RequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):

        parsed_url = urllib.parse.urlparse(self.path)
        query_params = urllib.parse.parse_qs(parsed_url.query)
        
        if 'code' in query_params:
            authorization_code = query_params['code'][0]

            self.send_response(200)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(b'<html><body>Authorization code received. You can close this window.</body></html>')

            retrieve_web_api_token(authorization_code)

            threading.Thread(target=self.server.shutdown).start()

        else:
            self.send_response(400)
            self.send_header('Content-type', 'text/html')
            self.end_headers()
            self.wfile.write(b'<html><body>Authorization code not found.</body></html>')


def run_redirect_server():
    httpd = HTTPServer(('localhost', 8888), RequestHandler)
    print('Starting HTTP redirection server')
    httpd.serve_forever()


def open_authenticate_page():
    authorize_url = 'https://accounts.spotify.com/authorize'

    params = {
        'client_id': client_id,
        'response_type': 'code',
        'redirect_uri': 'http://localhost:8888',
        "scope": "user-top-read playlist-read-collaborative user-read-email user-library-read user-read-private playlist-read-private",
    }

    auth_url = f"{authorize_url}?client_id={params['client_id']}&response_type={params['response_type']}&redirect_uri={params['redirect_uri']}&scope={params['scope']}"
    webbrowser.open(auth_url)


def authenticate():
    resolve_client_secret()

    redirect_server = threading.Thread(target=run_redirect_server)
    redirect_server.start()

    time.sleep(1)
    open_authenticate_page()

    redirect_server.join()

    return token


if __name__ == "__main__":
    authenticate()

