from typing import Optional

from mag_tools.log.logger import Logger
from mag_tools.model.convert_type import ConvertType
from mag_tools.model.log_type import LogType
from mag_tools.utils.common.time_probe import TimeProbe
from selenium.common.exceptions import InvalidSelectorException, NoSuchElementException, TimeoutException, \
    WebDriverException
from selenium.webdriver import ActionChains
from selenium.webdriver.common.by import By
from selenium.webdriver.remote.webelement import WebElement

from mag_test.bean.control import Control
from mag_test.bean.element_info import ElementInfo
from mag_test.core.app_driver import AppDriver
from mag_test.finder.driver_finder_utils import DriverFinderUtils
from mag_test.finder.element_finder_utils import ElementFinderUtils
from mag_test.model.control_type import ControlType
from mag_test.utils.event_utils import EventUtils
from mag_test.utils.tree_utils import TreeUtils
from mag_test.model.init_status import InitStatus
from mag_test.model.menu_type import MenuType
from mag_test.utils.element_utils import ElementUtils


class ElementFinder:
    @staticmethod
    def find(driver:AppDriver, element_info:ElementInfo):
        Logger.debug(f'开始查找控件：{element_info.main_info}')
        probe = TimeProbe.get_probe('查找控件')

        # 菜单
        if element_info.main_type == ControlType.MENU:
            element = ElementFinder.__find_menu(driver, element_info)
        # 窗口
        elif element_info.main_type == ControlType.WINDOW:
            element = ElementFinder.__find_window(driver, element_info)
        # 日期时间
        elif element_info.main_type == ControlType.DATETIME:
            element = ElementFinder.__find_datetime(driver, element_info)
        else:
            # 查找父控件并处理响应事件
            parent = ElementFinder.__find_parent(driver, element_info)

            # 查找主控件并处理响应事件
            main_element = ElementFinder.__find_main_element(driver, parent, element_info)

            # 查找子控件并处理响应事件
            if element_info.parent_info == ControlType.TABLE:
                child_element = ElementFinder.__find_table(driver, main_element)
            else:
                child_element = ElementFinder.__find_child_element(driver, main_element, element_info)

            # 查找弹出菜单并处理响应事件
            element = ElementFinder.__find_context_menu(driver, child_element, element_info.pop_menu)

            # # 按钮/拆分按钮
            # if element_info.main_type in {ControlType.BUTTON, ControlType.SPLIT_BUTTON}:
            #     element = ElementFinder.__find_split_button(driver, main_element, element_info)
            # # 组合框
            # elif element_info.main_type == ControlType.COMBO_BOX:
            #     element = ElementFinder.__find_combox_listbox_listview_treeview(driver, main_element, element_info, ControlType.LIST_ITEM, parent)
            # # 列表框
            # elif element_info.main_type == ControlType.LIST:
            #     element = ElementFinder.__find_combox_listbox_listview_treeview(driver, main_element, element_info, ControlType.LIST_ITEM, parent)
            # # 列表视图
            # elif element_info.main_type == ControlType.LIST_VIEW:
            #     element = ElementFinder.__find_combox_listbox_listview_treeview(driver, main_element, element_info, ControlType.LIST_ITEM, parent)
            # # 树视图
            # elif element_info.main_type == ControlType.TREE:
            #     element = ElementFinder.__find_combox_listbox_listview_treeview(driver, main_element, element_info, ControlType.TREE_ITEM, parent)
            # # 表格
            # elif element_info.main_type == ControlType.TABLE:
            #     element = ElementFinder.__find_table(driver, main_element, element_info)
            # # 简单控件（包括：工具栏、Pane、GROUP、TAB项等）
            # else:
            #     element = ElementFinder.__find_main_element(driver, element_info)

        probe.write_log()

        return element

    # @staticmethod
    # def __find_split_button(driver:AppDriver, main_element, element_info:ElementInfo):
    #     """
    #     查找按钮控件（包括：普通按钮和拆分按钮）
    #     参数：
    #     name 按钮名
    #     parent 父控件
    #     """
    #     return ElementFinder.__find_context_menu(driver, main_element, element_info.pop_menu)

    @staticmethod
    def __find_menu(driver:AppDriver, element_info:ElementInfo):
        """
        查找菜单控件
        参数：
        name 菜单及菜单项名，格式：菜单项名/子菜单项名/...
        parent_name 父控件名
        parent_control_type 父控件类型
        """
        items = element_info.menu_items

        element = None
        actions = ActionChains(driver)

        for index, item in enumerate(items):
            element = DriverFinderUtils.find_element_by_type_wait(driver, item, ControlType.MENU_ITEM)
            if index < len(items) - 1:
                actions.move_to_element(element).click().perform()
        return element

    # @staticmethod
    # def __find_combox_listbox_listview_treeview(driver:AppDriver, main_element: WebElement, element_info:ElementInfo, child_type: ControlType, parent:Optional[WebElement] = None):
    #     """
    #         查找树视图
    #         参数：
    #         name 树视图名，格式：树视图名/树节点名/菜单名，树视图名和菜单名可为空，只支持菜单模式的弹出菜单
    #     """
    #     if element_info.child_name:
    #         if element_info.child_action == InitStatus.EXPANDED:
    #             TreeUtils.expand_all(driver, main_element)
    #
    #         element = ElementFinderUtils.find_element_by_type(main_element, element_info.child_name, child_type)
    #     else:
    #         element = main_element
    #
    #     return ElementFinder.__find_context_menu(driver, element, element_info.pop_menu)

    @staticmethod
    def __find_table(main_element, element_info:ElementInfo):
        """
            查找表格
            参数：
            name 表格名，格式：表格名/文本框名/菜单名，表格名和菜单名可为空，只支持菜单模式的弹出菜单
            返回：TableRow的数组或Edit
        """
        if element_info.has_child and ConvertType.of_code(element_info.child_name) is None:
            element = None

            table_rows = ElementFinderUtils.find_elements_by_type(main_element, None, ControlType.TABLE_ROW)
            for row_index, row in enumerate(table_rows):
                cells = ElementFinderUtils.find_elements_by_type(row, None, ControlType.EDIT)
                for cell_index, cell in enumerate(cells):
                    if cell.text == element_info.child_name:
                        element = cell
                        break
        else:
            element = main_element

        return element

    @staticmethod
    def __find_datetime(driver:AppDriver, element_info:ElementInfo):
        """
        查找日期时间控件
        参数：
        name 日期时间控件名
        """
        parent = ElementFinder.__find_parent(driver, element_info)
        if parent:
            dt = ElementFinderUtils.find_element_by_class(parent, element_info.main_name, 'SysDateTimePick32')
        else:
            dt = DriverFinderUtils.find_element_by_class(driver, element_info.main_name, 'SysDateTimePick32')

        return dt

    @staticmethod
    def __find_window(driver:AppDriver, element_info: ElementInfo):
        """
        查找窗口
        参数：
        name 窗口名（关键词）
        """
        return driver.find_element(By.XPATH, f"//Window[contains(@Name, '{element_info.main_name}')]")
    
    @staticmethod
    def __find_context_menu(driver:AppDriver, element: WebElement, menu_item: Optional[Control]):
        if menu_item and menu_item.menu_type:
            actions = ActionChains(driver)
            actions.move_to_element(element).context_click(element).perform()

            try:

                menu = None
                if menu_item.menu_type == MenuType.CONTEXT:
                    menu = DriverFinderUtils.find_element_by_class(driver.root_driver, '上下文', '#32768')
                elif menu_item.menu_type == MenuType.POPUP:
                    menu = DriverFinderUtils.find_element_by_type(driver, '弹出窗口', ControlType.WINDOW)

                if menu:
                    element = ElementFinderUtils.find_element_by_type(menu, menu_item.name, ControlType.MENU_ITEM)
            except (NoSuchElementException, InvalidSelectorException, WebDriverException) :
                element = DriverFinderUtils.find_element_by_type(driver, menu_item.name, ControlType.MENU_ITEM)

            if element:
                Logger.debug(LogType.FRAME, f"控件[{element.text}]的菜单类型为：{menu_item.menu_type.desc}")

        return element

    @staticmethod
    def __find_child_element(driver: AppDriver, main_element: WebElement, element_info: ElementInfo):
        """
        查找树视图
        参数：
        name 树视图名，格式：树视图名/树节点名/菜单名，树视图名和菜单名可为空，只支持菜单模式的弹出菜单
        """
        if element_info.has_child:
            if element_info.child_action == InitStatus.EXPANDED:
                TreeUtils.expand_all(driver, main_element)

            element = ElementFinderUtils.find_element_by_type(main_element, element_info.child_name, element_info.child_type)
        else:
            element = main_element

        return element

    @staticmethod
    def __find_main_element(driver: AppDriver, parent: WebElement, element_info: ElementInfo):
        try:
            if element_info.main_id:
                if parent:
                    element = ElementFinderUtils.find_element_by_automation(parent, element_info.main_id)
                else:
                    element = DriverFinderUtils.find_element_by_automation_wait(driver, element_info.main_id)
            else:
                if parent:
                    element = ElementFinderUtils.find_element_by_type(parent, element_info.main_name, element_info.main_type)
                else:
                    element = DriverFinderUtils.find_element_by_type_wait(driver, element_info.main_name, element_info.main_type)

            if element and element_info.is_composite:
                offset = ElementUtils.get_parent_offset(element_info.value, element)

                EventUtils.click_offset(driver, element, offset)
        except NoSuchElementException as e:
            element = None
            Logger.debug(f'未找到主控件：{str(e)}')    # 模糊查找控件时，返回None正常
        except InvalidSelectorException as e:
            element = None
            Logger.debug(f'无效的控件选项：{str(e)}')  # 模糊查找控件时，返回None正常
        except TimeoutException as e:
            element = None
            Logger.debug(f'连接失败：{str(e)}')  # 模糊查找控件时，返回None正常
        except WebDriverException as e:
            element = None
            Logger.debug(f'连接失败或超时：{str(e)}')   # 模糊查找控件时，返回None正常

        return element

    @staticmethod
    def __find_parent(driver:AppDriver, element_info:ElementInfo):
        parent = None
        if element_info.need_to_find_parent:
            try:
                Logger.debug(f'开始查找父控件：{element_info.parent_info}')
                probe = TimeProbe.get_probe('查找父控件')

                if element_info.parent_id:
                    parent = DriverFinderUtils.find_element_by_automation_wait(driver, element_info.parent_id)
                elif element_info.parent_type:
                    parent = DriverFinderUtils.find_element_by_type_wait(driver, element_info.parent_name, element_info.parent_type)

                probe.write_log()
            except (NoSuchElementException, InvalidSelectorException, WebDriverException) as e:
                Logger.error(f'查找父控件失败：{element_info.parent_info}')
                raise e

        return parent