# -*- coding: utf-8 -*-

'''
tooner.launcher module
~~~~~~~~~~~~~~~~~~~~~~~~~~~

Functions and classes related to communicating with the Toontown
Rewritten API, logging in, and opening the launcher.
'''

import os
import platform
import subprocess
import time

import requests


class ToontownLauncher:
    '''Uses the given login information to communicate with the
    Toontown Rewritten API in an attempt to log in and launch the game.
    
    Args:
        directory (str):
            The directory of your Toontown Rewritten installation.
    
    Kwargs:
        attempts (int) [5]:
            The maximum number of attempts to connect before giving up.
            Accepts a None value to try infinitely, but this is not
            recommended.
        debug (bool) [True]:
            Whether to write information to the console detailing
            communication with the API.
    '''

    def __init__(self, directory, attempts=5, debug=False):
        '''Please see help(ToontownLauncher) for more info.'''

        self.directory = directory
        self.api_url = 'https://www.toontownrewritten.com/api/login?format=json'

        self._attempts = 0
        self.maximum_attempts = attempts

        self._debug = debug
        self._stdout = None if debug else subprocess.DEVNULL

    def play(self, **data):
        '''A more intuitively-named wrapper for the _connect method.'''

        return self._connect(**data)

    def _message(self, message):
        '''Print a message to the console.'''

        if self._debug:
            print(message)

    def _connect(self, **data):
        '''Communicate with the Toontown Rewritten API in an attempt to
        connect and log in.
        
        Kwargs:
            username (str):
                The username of the Toontown Rewritten account.
            password (str):
                The password of the Toontown Rewritten account.
            appToken (str):
                The ToonGuard code generated by an authenticator app.
                Only required if ToonGuard is activated for the
                Toontown Rewritten account.

        Returns:
            True: launch was successful.
            False: launch was unsuccessful.
            None: ToonGuard code is required.
        '''

        # Increment attempts counter and stop if the maximum has been reached
        self._attempts += 1
        if self.maximum_attempts and self._attempts > self.maximum_attempts:
            self._message(
                'The maximum number of attempts has been reached. '
                'Please try again.'
            )
            return False

        # If the connection request 
        app_token = data.pop('appToken', None)

        # Post a request and determine its success
        response = self._make_request(data)
        success = response.get('success', 'false')

        # If the connection was successful, proceed to launch the game
        if success == 'true':
            cookie = response.get('cookie', 'CookieNotFound')
            game_server = response.get('gameserver', 'ServerNotFound')
            self._message('Successful granted access.')
            self._launch_game(cookie, game_server)
            return True
        # If the success was partial, a ToonGuard code is required to log in
        elif success == 'partial':
            authorization_token = response.get('responseToken', None)
            if not app_token or not authorization_token:
                self._message('ToonGuard code required.')
                return None
            time.sleep(3)
            self._connect(appToken=app_token, authToken=authorization_token)
        # If success was delayed, the user was placed in a queue
        elif success == 'delayed':
            queue_token = response.get('queueToken', None)
            if not queue_token:
                self._message('Something went wrong. Please try again.')
                return False
            position = response.get('position')
            self._message(f'You are currently queued in position {position}.')
            time.sleep(3)
            self._connect(queueToken=queue_token)
        # Otherwise, the connection has failed
        else:
            self._message(
                'Connection failed. Something went wrong, but maybe it was '
                'just your username and password.'
            )
            return False

    def _make_request(self, data):
        '''Communicates with the Toontown Rewritten API to post a
        request.
        
        Args:
            data (dict):
                The data to send with the request.    
        '''

        # Post a request to the Toontown Rewritten API
        post = requests.post(
            self.api_url,
            data=data,
            headers={'Content-type': 'application/x-www-form-urlencoded'},
        )
        # Return the json data from the response
        return post.json()

    def _launch_game(self, play_cookie, game_server):
        '''Use the given response credentials to open the luancher and
        log into the game.
        
        Args:
            play_cookie (str):
                The cookie key used to log in. Received from the
                Toontown Rewritten API.
            game_server (str):
                The gameserver key used to log in. Received from the
                Toontown Rewritten API.
        '''

        # Determine the user's operating system
        operating_system = platform.system()
        # Change to the Toontown Rewritten directory
        os.chdir(self.directory)

        # Set the enironmental variables including login information
        os.environ['TTR_PLAYCOOKIE'] = play_cookie
        os.environ['TTR_GAMESERVER'] = game_server

        # Start the Toontown Rewritten process
        if operating_system == 'Windows':
            subprocess.Popen(
                args="TTREngine.exe",
                stdout=self._stdout,
                creationflags=0x08000000,
            )
        elif operating_system == 'Linux':
            # TODO: Linux features are currently untested.
            subprocess.Popen(args="./TTREngine", stdout=self._stdout)
        elif operating_system == 'Darwin':
            subprocess.Popen(args='./Toontown Rewritten', stdout=self._stdout)
        else:
            self._message('Your operating system is not currently supported.')
    
        # Let the user know the connection was successful
        self._message('Successfully connected.')
