from selenium import webdriver
from selenium.webdriver.remote import webelement
from selenium.webdriver.common.keys import Keys
from selenium.webdriver.common.action_chains import ActionChains
from selenium.webdriver.common.desired_capabilities import DesiredCapabilities
import time
from .utils import log, error
from threading import RLock
from typing import Any
from .settings import settings
from fake_useragent import UserAgent


def use_browser(org_func: Any):
    def wrapper(*args, **kwargs):
        browser = None
        for arg in args:
            if type(arg) is client:
                browser = arg
                break

        for _, value in kwargs.items():
            if type(value) is client:
                browser = value
                break

        # no custom browser given
        if browser is None:
            return org_func(*args, **kwargs)

        rv = None
        browser.use()

        try:
            rv = org_func(*args, **kwargs)
        except Exception as e:
            rv = None
            error(
                "exception in function: {} exception: {}".format(
                    org_func.__name__, str(e)
                )
            )

            log("reloading world.")
            url = browser.driver.current_url
            world = url.split("//")
            world = world[1]
            world = world.split(".")
            world = world[0]

            browser.get("https://{}.kingdoms.com".format(world))
        finally:
            browser.done()

            return rv

    return wrapper


class client:
    def __init__(self, debug: bool = False) -> None:
        self.driver: webdriver = None
        self.delay = None
        self._headless: bool = False
        self.lock = RLock()
        self.proxy: bool = False
        self.debug: bool = debug
        self.current_session_path: str = settings.current_session_path
        pass

    def chrome(self, path: str, proxy: str = "") -> None:
        options = webdriver.ChromeOptions()
        if proxy != "":
            self.proxy = True
            options.add_argument("proxy-server={}".format(proxy))

        options.add_argument("window-size=1500,1200")
        options.add_argument("log-level=3")

        self.driver = webdriver.Chrome(path, chrome_options=options)
        self.set_config()
        self.save_session()

    def remote(self) -> None:
        if not self.debug:
            log("debug mode is turned off, can't reuse old session")
            return

        file = open(self.current_session_path, "r")
        content = file.read()
        lines = content.split(";")
        url = lines[0]
        session = lines[1]

        self.driver = webdriver.Remote(
            command_executor=url, desired_capabilities=DesiredCapabilities.CHROME
        )
        self.driver.session_id = session

        self.set_config()

    def headless(self, path: str, proxy: str = "") -> None:
        ua = UserAgent()
        userAgent = ua.random
        options = webdriver.ChromeOptions()
        options.add_argument("headless")
        options.add_argument("window-size=1500,1200")
        options.add_argument("no-sandbox")
        options.add_argument("disable-dev-shm-usage")
        options.add_argument("disable-gpu")
        options.add_argument("log-level=3")
        options.add_argument(f"user-agent={userAgent}")

        if proxy != "":
            self.proxy = True
            options.add_argument("proxy-server={}".format(proxy))

        self.driver = webdriver.Chrome(path, chrome_options=options)
        self.set_config()
        self._headless = True

    def set_config(self) -> None:
        # set timeout to find an element in seconds
        self.driver.implicitly_wait(5 * settings.browser_speed)
        # set page load timeout in seconds
        self.driver.set_page_load_timeout(15 + settings.browser_speed)

    # region locks
    def use(self) -> None:
        self.lock.acquire()

    def done(self) -> None:
        self.lock.release()

    # endregion

    # region browser function
    def get(self, page: str) -> None:
        self.driver.get(page)

    def find(self, xpath: str, wait: float = 0) -> webelement:
        # todo wait x seconds until presencd of element
        wait = wait * settings.browser_speed
        self.sleep(wait)
        return self.driver.find_element_by_xpath(xpath)

    def finds(self, xpath: str, wait: float = 0) -> webelement:
        # todo wait x seconds until presencd of element
        wait = wait * settings.browser_speed
        self.sleep(wait)
        return self.driver.find_elements_by_xpath(xpath)

    def sleep(self, seconds: float) -> None:
        seconds = seconds * settings.browser_speed

        # reduce sleep time if in headless mode
        if self._headless:
            seconds = seconds / 2

        # doubles the sleep time, proxys are normaly way slower
        if self.proxy:
            seconds = seconds * 2

        time.sleep(seconds)

    def click(self, element: webelement, wait: float = 0.5) -> None:
        ActionChains(self.driver).move_to_element(element).click().perform()

        wait = wait * settings.browser_speed
        self.sleep(wait)

    def click_v2(self, element: webelement, wait: float = 0.5) -> None:
        ActionChains(self.driver).move_to_element(element).click(element).perform()

        wait = wait * settings.browser_speed
        self.sleep(wait)

    def hover(self, element: webelement, wait: float = 0.5) -> None:
        ActionChains(self.driver).move_to_element(element).perform()

        wait = wait * settings.browser_speed
        self.sleep(wait)

    def scroll_down(self, element: webelement) -> None:
        element.send_keys(Keys.PAGE_DOWN)

    def refresh(self) -> None:
        self.driver.refresh()

    def current_url(self) -> str:
        return self.driver.current_url

    # endregion

    # region session
    def save_session(self) -> None:
        if not self.debug:
            return

        url = self.driver.command_executor._url
        session = self.driver.session_id

        filename = self.current_session_path
        semi = ";"

        content = url + semi + session

        try:
            file = open(filename, "w")
            file.write(content)
            file.close()
        except:
            log("Error saving Session")

    def write_source(self) -> None:
        file = open("./source.html", "w")
        file.write(self.driver.page_source)
        file.close()

    # endregion