#!/usr/bin/env python

"""Example program that demonstrates the flow for retrieving a refresh token.

In order for this example to work your application's redirect URI must be set to
http://localhost:8080.

This tool can be used to conveniently create refresh tokens for later use with your web
application OAuth2 credentials.

"""

import asyncio
import os
import random
import socket
import sys

import asyncprawcore


def receive_connection():
    """Wait for and then return a connected socket..

    Opens a TCP connection on port 8080, and waits for a single client.

    """
    server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
    server.bind(("localhost", 8080))
    server.listen(1)
    client = server.accept()[0]
    server.close()
    return client


def send_message(client, message):
    """Send message to client and close the connection."""
    print(message)
    client.send(f"HTTP/1.1 200 OK\r\n\r\n{message}".encode())
    client.close()


async def main():
    """Provide the program's entry point when directly executed."""
    if len(sys.argv) < 2:
        print(f"Usage: {sys.argv[0]} SCOPE...")
        return 1

    requestor = asyncprawcore.Requestor("asyncprawcore_refresh_token_example")
    try:
        authenticator = asyncprawcore.TrustedAuthenticator(
            requestor,
            os.environ["PRAWCORE_CLIENT_ID"],
            os.environ["PRAWCORE_CLIENT_SECRET"],
            "http://localhost:8080",
        )

        state = str(random.randint(0, 65000))  # noqa: S311
        url = authenticator.authorize_url("permanent", sys.argv[1:], state)
        print(url)

        client = receive_connection()
        data = client.recv(1024).decode("utf-8")
        param_tokens = data.split(" ", 2)[1].split("?", 1)[1].split("&")
        params = dict([token.split("=") for token in param_tokens])

        if state != params["state"]:
            send_message(
                client,
                f"State mismatch. Expected: {state} Received: {params['state']}",
            )
            return 1
        if "error" in params:
            send_message(client, params["error"])
            return 1

        authorizer = asyncprawcore.Authorizer(authenticator)
        await authorizer.authorize(params["code"])

        send_message(client, f"Refresh token: {authorizer.refresh_token}")
    finally:
        await requestor.close()
    return 0


if __name__ == "__main__":
    sys.exit(asyncio.run(main()))
