╔───────────────────────────────────────────────────────────────────────────────────────────────────────────╗
          _____                    _____                    _____          
         /\    \                  /\    \                  /\    \         
        /::\    \                /::\    \                /::\    \        
       /::::\    \              /::::\    \              /::::\    \       
      /::::::\    \            /::::::\    \            /::::::\    \      
     /:::/\:::\    \          /:::/\:::\    \          /:::/\:::\    \     
    /:::/  \:::\    \        /:::/__\:::\    \        /:::/__\:::\    \    
   /:::/    \:::\    \      /::::\   \:::\    \      /::::\   \:::\    \   
  /:::/    / \:::\    \    /::::::\   \:::\    \    /::::::\   \:::\    \  
 /:::/    /   \:::\ ___\  /:::/\:::\   \:::\    \  /:::/\:::\   \:::\____\ 
/:::/____/  ___\:::|    |/:::/  \:::\   \:::\____\/:::/  \:::\   \:::|    |
\:::\    \ /\  /:::|____|\::/    \:::\  /:::/    /\::/   |::::\  /:::|____|
 \:::\    /::\ \::/    /  \/____/ \:::\/:::/    /  \/____|:::::\/:::/    / 
  \:::\   \:::\ \/____/            \::::::/    /         |:::::::::/    /  
   \:::\   \:::\____\               \::::/    /          |::|\::::/    /   
    \:::\  /:::/    /               /:::/    /           |::| \::/____/    
     \:::\/:::/    /               /:::/    /            |::|  ~|          
      \::::::/    /               /:::/    /             |::|   |          
       \::::/    /               /:::/    /              \::|   |          
        \::/____/                \::/    /                \:|   |          
                                  \/____/                  \|___|                                                                                
╚───────────────────────────────────────────────────────────────────────────────────────────────────────────╝
import sys
import os
from pathlib import Path
from time import sleep

from selenium import webdriver
import pandas
import json

from selenium.webdriver.chrome.options import Options
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import Select, WebDriverWait
from selenium.common.exceptions import TimeoutException

driver = None
current_proxy = None
proxy_timeout = False
delay = 10
page_elements = None


def follow_channel(username, follow_channel_name):
    global delay

    print("[{}] Trying to follow: [{}]".format(username, follow_channel_name))

    try:
        driver.get("https://www.twitch.tv/{}".format(follow_channel_name))

        follow_button = driver.find_element_by_xpath(
            get_page_element("follow_button"))

        follow_button.click()

        # wait for request
        sleep(5)

        print("[{}] Successfully followed: [{}]".format(
            username, follow_channel_name))

        return True
    except:
        # checks if channel is already following
        try:
            driver.find_element_by_xpath(get_page_element("unfollow_button"))

            print("[{}] Is already following: [{}], moving on the next user!!!".format(
                username, follow_channel_name))

            return True
        except:
            try:
                driver.find_element_by_xpath(
                    get_page_element("nonexistent_channel"))

                print("No channel: [{}] found, exiting!!!".format(
                    follow_channel_name))

                exit()
            except:
                pass

            return False


def sign_in(username, password):
    global proxy_timeout
    global delay

    print("[{}] Singing in...".format(username))

    try:
        driver.get("https://www.twitch.tv/login")

        username_input = WebDriverWait(driver, delay).until(
            EC.presence_of_element_located((By.XPATH, get_page_element("username_input"))))

        password_input = driver.find_element_by_xpath(
            get_page_element("password_input"))
        login_button = driver.find_element_by_xpath(
            get_page_element("login_button"))

        username_input.clear()
        username_input.send_keys(username)
        password_input.clear()
        password_input.send_keys(password)

        login_button.click()

        WebDriverWait(driver, delay).until(EC.presence_of_element_located(
            (By.XPATH, get_page_element("my_account"))))

        print("[{}] Successfully signed in.\n".format(username))
        return True
    except TimeoutException:
        try:
            driver.find_element_by_xpath(get_page_element("auth_failed"))
            print("[{}] Incorrect credentials, changing account!!!".format(username))
            return False
        except:
            try:
                driver.find_element_by_xpath(get_page_element("recaptcha"))
                print("[{}] Recaptcha, changing proxy!!!".format(username))
            except:
                pass

            proxy_timeout = True
            return False


def main():
    global proxy_timeout
    global page_elements

    follow_channel_name = input("What channel should I follow? : ")

    # load page_elements json file
    with open(get_full_path("/page_elements.json")) as page_elements_file:
        page_elements = json.load(page_elements_file)

    accounts_csv_path = get_full_path("/data/accounts.csv")
    accounts_csv = pandas.read_csv(accounts_csv_path, sep=',', dtype="str")

    # define accounts.csv columns
    username_rows = accounts_csv.username
    password_rows = accounts_csv.password

    # go through every account in .csv
    for i, (username, password) in enumerate(zip(username_rows, password_rows)):
        if pandas.isnull(username) is False or pandas.isnull(password) is False:
            print("--------------------------------")

            run_driver(True)

            sign_in_status = sign_in(username, password)

            while sign_in_status is False and proxy_timeout:
                print("--------------------------------")
                print("Time expired, changing proxy...")
                print("Using previous account: [{}]\n".format(username))

                run_driver(True)

                sign_in_status = sign_in(username, password)

            if sign_in_status:
                if follow_channel(username, follow_channel_name):
                    accounts_csv.at[i,
                                    'following_channel'] = follow_channel_name
                    accounts_csv.at[i, 'used_proxy'] = current_proxy
                    accounts_csv.to_csv(accounts_csv_path, sep=',',
                                        index=False, index_label=False)
                else:
                    accounts_csv.at[i, 'following_channel'] = "ERROR"
                    accounts_csv.to_csv(accounts_csv_path, sep=',',
                                        index=False, index_label=False)

                    print("[{}] An error ocurred while trying to follow: [{}]!!!".format(
                        username, follow_channel_name))
    print("--------------------------------")
    print("No more accounts!!!")
    print("--------------------------------")


def get_page_element(input):
    global page_elements

    return page_elements[input]["value"]


def get_full_path(file_path):
    return str(Path("{}{}".format(os.getcwd(), file_path)))


def find_available_proxy():
    proxies_csv_path = get_full_path("/data/proxies.csv")
    proxies_csv = pandas.read_csv(proxies_csv_path, sep=',', dtype="str")

    # define proxies.csv columns
    proxy_rows = proxies_csv.proxy
    status_rows = proxies_csv.status

    # go through every proxy in .csv and check if it is available to use
    for i, (proxy, status) in enumerate(zip(proxy_rows, status_rows)):
        if i == len(proxy_rows) - 1 and status == "USED":
            print("--------------------------------")
            print("No more proxies!!!")
            print("--------------------------------")
            exit()
        elif pandas.isnull(status):
            proxies_csv.at[i, 'status'] = "USED"
            proxies_csv.to_csv(proxies_csv_path, sep=',',
                               index=False, index_label=False)
            return proxy


def run_driver(run_with_proxy):
    global driver
    global current_proxy

    # stop driver before changing it
    stop_driver()

    chrome_options = Options()
    chrome_options.add_argument("--lang=en-US,en")
    chrome_options.add_argument("--disable-notifications")

    if run_with_proxy:
        current_proxy = find_available_proxy()

        if current_proxy:
            chrome_options.add_argument(
                "--proxy-server={}".format(current_proxy))
            print("Using proxy: [{}]".format(current_proxy))

    current_os = sys.platform

    chrome_driver_file_name = ""
    if current_os in "darwin":
        chrome_driver_file_name = "chromedriver_mac64"
    elif current_os in "linux":
        chrome_driver_file_name = "chromedriver_linux64"
    elif current_os in "win32":
        chrome_driver_file_name = "chromedriver_win32.exe"

    chrome_driver_path = get_full_path(
        "/drivers/{}".format(chrome_driver_file_name))

    driver = webdriver.Chrome(options=chrome_options,
                              executable_path=chrome_driver_path)
    driver.set_window_size(880, 720)
    driver.set_window_position(0, 0)
    driver.set_page_load_timeout(20)


def stop_driver():
    global driver

    if driver is None:
        pass
    else:
        driver.quit()
        driver = None


def exit():
    stop_driver()
    input("Pres 'Enter' to Exit")
    sys.exit()


if __name__ == '__main__':
    main()
    exit()