import getpass
import os
import browser_cookie3
import requests
from cookies import get_cookies_path, save_cookies_to_file
from exceptions import StreamerDoesNotExistException
from twitch_data import get_client_id, get_channel_id


# Based on https://github.com/derrod/twl.py
# Original Copyright (c) 2020 Rodney
# The MIT License (MIT)


def check_login():
    if not os.path.exists(get_cookies_path()):
        twitch_login = TwitchLogin()
        success = twitch_login.login_flow()
        if success:
            twitch_login.save_cookies()
            print("Login successful!")
        return success
    else:
        return True


class TwitchLogin:
    def __init__(self):
        self.token = None
        self.login_check_result = False
        self.session = requests.session()
        self.session.headers.update({'Client-ID': get_client_id()})
        self.username = None
        self.user_id = None
        self.email = None

    def login_flow(self):
        print("You'll have to login to Twitch!")

        post_data = {
            'client_id': get_client_id(),
            'undelete_user': False,
            'remember_me': True
        }

        use_backup_flow = False

        while True:
            self.username = input('Enter Twitch username: ')
            password = getpass.getpass('Enter Twitch password: ')

            post_data['username'] = self.username
            post_data['password'] = password

            while True:
                # Try login without 2FA
                login_response = self.send_login_request(post_data)

                if 'captcha_proof' in login_response:
                    post_data['captcha'] = dict(proof=login_response['captcha_proof'])

                if 'error_code' in login_response:
                    err_code = login_response['error_code']
                    if err_code == 3011 or err_code == 3012:  # missing 2fa token
                        if err_code == 3011:
                            print('Two factor authentication enabled, please enter token below.')
                        else:
                            print('Invalid two factor token, please try again.')

                        twofa = input('2FA token: ')
                        post_data['authy_token'] = twofa.strip()
                        continue

                    elif err_code == 3022 or err_code == 3023:  # missing 2fa token
                        if err_code == 3022:
                            print('Login Verification code required.')
                            self.email = login_response['obscured_email']
                        else:
                            print('Invalid Login Verification code entered, please try again.')

                        twofa = input(f'Please enter the 6-digit code sent to {self.email}: ')
                        post_data['twitchguard_code'] = twofa.strip()
                        continue

                    elif err_code == 3001:  # invalid password
                        print('Invalid username or password, please try again.')
                        break
                    elif err_code == 1000:
                        print('Console login unavailable (CAPTCHA solving required).')
                        use_backup_flow = True
                        break
                    else:
                        print(f'Unknown error: {login_response}')
                        raise NotImplementedError(f'Unknown TwitchAPI error code: {err_code}')

                if 'access_token' in login_response:
                    self.set_token(login_response['access_token'])
                    return self.check_login()

            if use_backup_flow:
                break

        if use_backup_flow:
            self.set_token(self.login_flow_backup())
            return self.check_login()

        return False

    def set_token(self, new_token):
        self.token = new_token
        self.session.headers.update({'Authorization': f'Bearer {self.token}'})

    def send_login_request(self, json_data):
        r = self.session.post('https://passport.twitch.tv/login', json=json_data)
        j = r.json()
        return j

    def login_flow_backup(self):
        """Backup OAuth login flow in case manual captcha solving is required"""
        browser = input("What browser do you use? Chrome (1), Firefox (2), Other (3): ").strip()
        if browser not in ("1", "2"):
            print("Your browser is unsupported, sorry.")
            return None

        input("Please login inside your browser of choice (NOT incognito mode) and press Enter...")
        print("Loading cookies saved on your computer...")
        twitch_domain = ".twitch.tv"
        if browser == "1":  # chrome
            cookie_jar = browser_cookie3.chrome(domain_name=twitch_domain)
        else:
            cookie_jar = browser_cookie3.firefox(domain_name=twitch_domain)
        cookies_dict = requests.utils.dict_from_cookiejar(cookie_jar)
        self.username = cookies_dict.get("login")
        return cookies_dict.get("auth-token")

    def check_login(self):
        if self.login_check_result:
            return self.login_check_result
        if self.token is None:
            return False

        try:
            self.user_id = get_channel_id(self.username)
            self.login_check_result = True
        except StreamerDoesNotExistException:
            self.login_check_result = False
        return self.login_check_result

    def save_cookies(self):
        cookies_dict = self.session.cookies.get_dict()
        cookies_dict["auth-token"] = self.token
        if "persistent" not in cookies_dict:  # saving user id cookies
            cookies_dict["persistent"] = self.user_id
        save_cookies_to_file(cookies_dict)
