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

__author__ = 'n_kovganko@wargaming.net'

import json
from time import sleep

from wgc_core.exceptions import WGCException, WebSocketConnectionClosed, WGCDoesntGetResponseException
from wgc_client.ui.elements.abstract_element import AbstractElement


class WebElement(AbstractElement):

    def click(self, wait_response=True, timeout=10, index=0, ignore_exc=False):
        js_command = f'{self.selector}[{index}].click()'
        result = self.client.execute_js(js_command,
                                        dont_wait_response=not wait_response,
                                        timeout=timeout,
                                        check_crash=True, provider=self.provider)
        if not ignore_exc:
            if result and result != 'undefined':
                raise WGCException(
                    'Something goes wrong when clicking on "%s". Error: %s' % (
                        self.element_name, result))

    def double_click(self):
        pass

    @property
    def is_element_displayed(self):
        try:
            index = '' if self.index is None else '[%d]' % self.index
            result = self.client.execute_js(
                '%s%s.length != 0' % (self.selector, index), timeout=15, provider=self.provider)
            return result == 'true'
        except (WebSocketConnectionClosed, WGCDoesntGetResponseException):
            return False

    @property
    def is_checkbox_checked(self):
        result = self.client.execute_js(f'{self.selector}[{self.index}].checked', provider=self.provider)
        return result == 'true'

    @property
    def is_element_present(self):
        try:
            result = self.client.execute_js(f'{self.selector}[{self.index}]', provider=self.provider)
            return result != 'undefined'
        except (WebSocketConnectionClosed, WGCDoesntGetResponseException):
            return False

    def get_text(self):
        text = self.client.execute_js(f'{self.selector}[{self.index}].innerText', provider=self.provider)
        if 'TypeError' in text:
            return ''
        return text

    def get_html_text(self):
        length = self.client.execute_js('%s.length' % self.selector, provider=self.provider)
        if not length.isdigit():
            raise WGCException('Something goes wrong when getting text on '
                               '"%s". Error: %s' % (self.element_name, length))
        length = int(length)
        result = []
        for i in range(length):
            text = self.client.execute_js('%s[%s].innerHTML' % (self.selector, i), provider=self.provider)
            if 'TypeError' not in text:
                result.append(text)

        result = result[0] if len(result) == 1 else result
        return result or ''

    def get_value(self):
        return self.client.execute_js(f'{self.selector}[{self.index}].value', provider=self.provider)
    
    def get_display_property(self):
        return self.client.execute_js(f'getComputedStyle({self.selector}[{self.index}]).display')
    
    def get_src_property(self):
        return self.client.execute_js(f'getComputedStyle({self.selector}[{self.index}]).src')
        
    def set_text(self, text, index=0):
        result = self.client.execute_js(f'{self.selector}[{index}].value = "%s"' % text.replace('"', '\\"'),
                                        provider=self.provider)
        if result.replace('\\', '') != text.replace('\\', ''):
            raise WGCException('Something goes wrong when setting text on '
                               '"%s". Error: %s' % (self.element_name, result))

        self.trigger_event('change', index=index)

    def react_set_text(self, text, index=0):
        if index == 0:
            selector = self.selector.replace('querySelectorAll', 'querySelector')
        else:
            selector = f'{self.selector}[{index}]'
        result = self.client.execute_js(f'triggerInput({selector}, "{text}");', provider=self.provider)
        if result != 'undefined':
            raise WGCException('Something goes wrong when setting text on '
                               '"%s". Error: %s' % (self.element_name, result))
        
    def react_mouse_down(self):
        self.client.execute_js(f'{self.selector}[{self.index}].dispatchEvent('
                               f'new MouseEvent(\'mousedown\', {{ bubbles: true }}))', provider=self.provider)
        
    def react_mouse_up(self):
        self.client.execute_js(f'{self.selector}[{self.index}].dispatchEvent('
                               f'new MouseEvent(\'mouseup\', {{ bubbles: true }}))', provider=self.provider)
        
    def react_click(self):
        self.client.execute_js(f'{self.selector}[{self.index}].dispatchEvent('
                               f'new MouseEvent(\'click\', {{ bubbles: true }}))', provider=self.provider)
        
    def react_mouseover(self):
        self.client.execute_js(f'{self.selector}[{self.index}].dispatchEvent('
                               f'new MouseEvent(\'mouseover\', {{ bubbles: true }}))', provider=self.provider)
        
    def react_mouseleave(self):
        self.client.execute_js(f'{self.selector}[{self.index}].dispatchEvent('
                               f'new MouseEvent(\'mouseleave\', {{ bubbles: true }}))', provider=self.provider)

    def get_attribute(self, attribute_name, index=0):
        result = self.client.execute_js('%s[%d].getAttribute("%s")' %
                                        (self.selector, index, attribute_name), provider=self.provider)
        result = None if result == 'TypeError: Cannot read property \'outerHTML\' of null' else result
        return result

    def get_property_value(self, attribute_name, index=0):
        result = self.client.execute_js(
            f'window.getComputedStyle({self.selector}[{index}]).getPropertyValue("{attribute_name}")',
            provider=self.provider)
        if 'TypeError: Failed to execute' in result:
            return None
        return result
    
    def get_style_value(self, attribute_name, index=0):
        result = self.client.execute_js(
            f'{self.selector}[{index}].style.{attribute_name}', provider=self.provider)
        if 'TypeError: Failed to execute' in result:
            return None
        return result

    def trigger_event(self, event, params=None, index=0):
        angular_event = 'angular.element.Event("%s", %s)' % \
                        (event, params) if params else '"%s"' % event
        try:
            self.client.execute_js(
                'angular.element(%s[%d]).trigger(%s)' %
                (self.selector, index, angular_event), dont_wait_response=True, provider=self.provider)
        except (WebSocketConnectionClosed, WGCDoesntGetResponseException):
            pass

    def get_elements_count(self):
        result = self.client.execute_js('%s.length' % self.selector, provider=self.provider)
        try:
            return int(result)
        except ValueError:
            return 0

    def scroll_to(self):
        self.client.execute_js(f'{self.selector}[{self.index}].scrollIntoView()', provider=self.provider)

    def hover_on_element(self):
        self.mouseleave_on_element()
        self.mouseenter_on_element()

    def mouseenter_on_element(self):
        self.client.execute_js('angular.element(%s).mouseenter()' %
                               self.selector, provider=self.provider)

    def mouseover_on_element(self):
        self.client.execute_js('angular.element(%s).mouseover()' %
                               self.selector, provider=self.provider)

    def mouseleave_on_element(self):
        self.client.execute_js('angular.element(%s).mouseleave()' %
                               self.selector, provider=self.provider)

    def get_element_color(self):
        color = self.client.execute_js('angular.element(%s).css("color")' %
                                       self.selector, provider=self.provider)
        return color

    def get_element_background_color(self):
        bg_color = self.client.execute_js(
            'angular.element(%s).css("background-color")' % self.selector, provider=self.provider)
        return bg_color

    def set_checkbox_state(self, state):
        self.client.execute_js('angular.element(%s).prop("checked", %s)' % (
            self.selector, str(state).lower()), provider=self.provider)

    def set_focus(self):
        self.client.execute_js(f'{self.selector}[{self.index}].focus()', provider=self.provider)
        self.client.execute_js(f'{self.selector}[{self.index}].click()', provider=self.provider)
        sleep(.75)

    def get_bounding_client_rect(self, index=0):
        result = self.client.execute_js('JSON.stringify(angular.element(%s)[%s].'
                                        'getBoundingClientRect())' % (self.selector, index), provider=self.provider)
        try:
            result = json.loads(result)
        except ValueError:
            result = {}
        return result
