#!/usr/bin/env python3
import logging
import os
import sys
from typing import List

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow


def get_credentials(
    tokens_path: str,
    client_secret_path: str,
    scopes: List[str],
    noauth_local_webserver: bool = False,
) -> Credentials:
    """
    Writes google tokens to a json file, using the client secret file (for the OAuth flow),
    and the refresh token.

    If the tokens file exists and is valid, nothing needs to be done.
    If the tokens file exists, but the auth token is expired (expiry duration of auth token
    is 1 hour), the refresh token is used to get a new token.
    If the tokens file does not exist, or is invalid, the OAuth2 flow is triggered.

    The OAuth2 flow needs the client secret file, and requires the user to grant access to
    the application via a browser authorization page, for the first run.
    The authorization can be done either automatically using a local web server,
    or manually by copy-pasting the auth code from the browser into the command line.

    The fetched tokens are written to storage in a json file, for reference by other scripts.
    """
    creds = None
    if os.path.exists(tokens_path):
        creds = Credentials.from_authorized_user_file(tokens_path, scopes)
    if not creds or not creds.valid:
        if creds and creds.expired and creds.refresh_token:
            creds.refresh(Request())
        else:
            if not os.path.exists(client_secret_path):
                logging.error(
                    "Unable to find the client secret file.\nPlease ensure that you have downloaded the client secret file from Google. Either place the client secret file at %s, or use the --client-secret-file option to specify the path to the client secret file.",
                    client_secret_path,
                )
                sys.exit(1)
            flow = InstalledAppFlow.from_client_secrets_file(
                client_secret_path,
                scopes,
                redirect_uri="urn:ietf:wg:oauth:2.0:oob" if noauth_local_webserver else None,
            )

            if noauth_local_webserver:
                auth_url, _ = flow.authorization_url(access_type="offline")
                auth_code = input(
                    f"Please visit this URL to authorize this application:\n{auth_url}\nEnter the authorization code: "
                )
                flow.fetch_token(code=auth_code)
                creds = flow.credentials
            else:
                creds = flow.run_local_server(port=0)
        with open(tokens_path, "w") as token_file:
            token_file.write(creds.to_json())
            logging.info("Saved tokens to %s", tokens_path)
    return creds
