import sys
from uiautomator2 import UiObjectNotFoundError
from core.assertion import LMAssert
from core.app.device import Operation


class Assertion(Operation):
    """断言类操作"""

    def assert_ele_exists(self, element, assertion, expect):
        """断言元素存在"""
        try:
            actual = self.find_element(element).exists
            self.test.debugLog("成功获取元素exists:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取元素exists")
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def assert_ele_text(self, system, element, assertion, expect):
        """断言元素文本"""
        try:
            if system == "android":
                actual = self.find_element(element).get_text()
            else:
                actual = self.find_element(element).text
            self.test.debugLog("成功获取元素text:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取元素text")
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def assert_ele_attribute(self, element, attribute, assertion, expect):
        """断言元素属性"""
        try:
            actual = self.find_element(element).info[attribute]
            self.test.debugLog("成功获取元素%s属性:%s" % (attribute, str(actual)))
        except Exception as e:
            self.test.errorLog("无法获取元素%s属性" % attribute)
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def assert_ele_center(self, system, element, assertion, expect):
        """断言元素位置"""
        try:
            if system == "android":
                x, y = self.find_element(element).center()
                actual = (x, y)
            else:
                x, y = self.find_element(element).bounds.center
                actual = (x, y)
            self.test.debugLog("成功获取元素位置:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取元素位置")
            raise e
        else:
            result, msg = LMAssert(assertion, str(actual), expect).compare()
            return result, msg

    def assert_ele_x(self, system, element, assertion, expect):
        """断言元素X坐标"""
        try:
            if system == "android":
                x, y = self.find_element(element).center()
                actual = x
            else:
                x, y = self.find_element(element).bounds.center
                actual = x
            self.test.debugLog("成功获取元素X坐标:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取元素X坐标")
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def assert_ele_y(self, system, element, assertion, expect):
        """断言元素Y坐标"""
        try:
            if system == "android":
                x, y = self.find_element(element).center()
                actual = y
            else:
                x, y = self.find_element(element).bounds.center
                actual = y
            self.test.debugLog("成功获取元素Y坐标:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取元素Y坐标")
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def assert_alert_exists(self, assertion, expect):
        """断言弹框存在 IOS专属"""
        try:
            actual = self.device.alert.exists
            self.test.debugLog("成功获取弹框exists:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取弹框exists")
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def assert_alert_text(self, assertion, expect):
        """断言弹框文本 IOS专属"""
        try:
            actual = self.device.alert.text
            self.test.debugLog("成功获取弹框文本:%s" % str(actual))
        except Exception as e:
            self.test.errorLog("无法获取弹框文本")
            raise e
        else:
            result, msg = LMAssert(assertion, actual, expect).compare()
            return result, msg

    def custom(self, **kwargs):
        """自定义"""
        code = kwargs["code"]
        names = locals()
        names["element"] = kwargs["element"]
        names["data"] = kwargs["data"]
        names["device"] = self.device
        names["test"] = self.test
        try:
            """断言操作需要返回被断言的值 以sys_return(value)返回"""
            def print(*args, sep=' ', end='\n', file=None, flush=False):
                if file is None or file in (sys.stdout, sys.stderr):
                    file = names["test"].stdout_buffer
                self.print(*args, sep=sep, end=end, file=file, flush=flush)

            def sys_return(res):
                names["_exec_result"] = res

            def sys_get(name):
                if name in names["test"].context:
                    return names["test"].context[name]
                elif name in names["test"].common_params:
                    return names["test"].common_params[name]
                else:
                    raise KeyError("不存在的公共参数或关联变量: {}".format(name))

            def sys_put(name, val, ps=False):
                if ps:
                    names["test"].common_params[name] = val
                else:
                    names["test"].context[name] = val

            exec(code)
            self.test.debugLog("成功执行 %s" % kwargs["trans"])
        except UiObjectNotFoundError as e:
            raise e
        except Exception as e:
            self.test.errorLog("无法执行 %s" % kwargs["trans"])
            raise e
        else:
            result, msg = LMAssert(kwargs["data"]["assertion"], names["_exec_result"], kwargs["data"]["expect"]).compare()
            return result, msg

