# from objectmaphelper import RegularExpression
from types import SimpleNamespace
from appium.webdriver.common.appiumby import AppiumBy as By
from selenium.webdriver.common.keys import Keys
from selenium.common.exceptions import NoSuchElementException

from helpers.FilesHelper import build_conflicted_regex
from helpers.ConfigHelper import get_config
from helpers.AppHelper import app


class Activity:
    TAB_CONTAINER = SimpleNamespace(by=None, selector=None)
    SUBTAB_CONTAINER = SimpleNamespace(
        by=By.CLASS_NAME, selector="[page tab | {tab_name}]"
    )
    NOT_SYNCED_TABLE = SimpleNamespace(by=None, selector=None)
    LOCAL_ACTIVITY_FILTER_BUTTON = SimpleNamespace(by=By.NAME, selector="Filter")
    LOCAL_ACTIVITY_FILTER_OPTION_SELECTOR = SimpleNamespace(by=By.NAME, selector=None)
    LOCAL_ACTIVITY_TABLE = SimpleNamespace(by=By.NAME, selector="Local activity table")
    FILTER_BUTTON_SELECTED_STATE = SimpleNamespace(
        by=By.XPATH, selector="//*[contains(@name, '1 Filter')]"
    )
    NOT_SYNCED_FILTER_BUTTON = SimpleNamespace(by=None, selector=None)
    NOT_SYNCED_FILTER_OPTION_SELECTOR = SimpleNamespace(by=None, selector=None)
    SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR = SimpleNamespace(by=None, selector=None)
    NOT_SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR = SimpleNamespace(by=None, selector=None)
    SYNCED_ACTIVITY_STATUS = SimpleNamespace(by=By.NAME, selector=None)

    @staticmethod
    def get_not_synced_file_selector(resource):
        return {
            "column": 1,
            "container": Activity.NOT_SYNCED_TABLE,
            "text": resource,
            "type": "QModelIndex",
        }

    @staticmethod
    def get_not_synced_status(row):
        return squish.waitForObjectExists(
            {
                "column": 6,
                "row": row,
                "container": Activity.NOT_SYNCED_TABLE,
                "type": "QModelIndex",
            }
        ).text

    @staticmethod
    def click_tab(tab_name):
        selector = Activity.SUBTAB_CONTAINER.selector.format(tab_name=tab_name)
        app().find_element(Activity.SUBTAB_CONTAINER.by, selector).click()

    @staticmethod
    def check_file_exist(filename):
        squish.waitForObjectExists(
            Activity.get_not_synced_file_selector(
                RegularExpression(build_conflicted_regex(filename))
            )
        )

    @staticmethod
    def is_resource_blacklisted(filename):
        result = squish.waitFor(
            lambda: Activity.has_sync_status(filename, "Blacklisted"),
            get_config("maxSyncTimeout") * 1000,
        )
        return result

    @staticmethod
    def is_resource_ignored(filename):
        result = squish.waitFor(
            lambda: Activity.has_sync_status(filename, "File Ignored"),
            get_config("maxSyncTimeout") * 1000,
        )
        return result

    @staticmethod
    def is_resource_excluded(filename):
        result = squish.waitFor(
            lambda: Activity.has_sync_status(filename, "Excluded"),
            get_config("maxSyncTimeout") * 1000,
        )
        return result

    @staticmethod
    def has_sync_status(filename, status):
        try:
            app().find_element(Activity.SYNCED_ACTIVITY_STATUS.by, status)
            return True
        except NoSuchElementException:
            return False

    @staticmethod
    def select_synced_filter(sync_filter):
        menu = app().find_element(
            Activity.LOCAL_ACTIVITY_FILTER_BUTTON.by,
            Activity.LOCAL_ACTIVITY_FILTER_BUTTON.selector,
        )
        menu.click()

        # NOTE: Filter options are not visible in the accessibility tree.
        # As a workaround, select the second filter option (which is an account filter).
        # This means we cannot select a specific account filter for now.
        menu.send_keys(Keys.ARROW_DOWN)
        menu.send_keys(Keys.ARROW_DOWN)
        menu.send_keys(Keys.ENTER)
        # confirm filter is applied
        app().find_element(
            Activity.FILTER_BUTTON_SELECTED_STATE.by,
            Activity.FILTER_BUTTON_SELECTED_STATE.selector,
        )

    @staticmethod
    def get_synced_file_selector(resource):
        return {
            "column": Activity.get_synced_table_column_number_by_name("File"),
            "container": Activity.LOCAL_ACTIVITY_TABLE,
            "text": resource,
            "type": "QModelIndex",
        }

    @staticmethod
    def get_synced_table_column_number_by_name(column_name):
        return squish.waitForObject(
            {
                "container": Activity.SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR,
                "text": column_name,
                "type": "HeaderViewItem",
                "visible": True,
            }
        )["section"]

    @staticmethod
    def has_activity(resource, action, account):
        try:
            row = app().find_element(By.NAME, resource)
            row_y = row.rect['y']
            # check other properties using current row position
            action_cells = app().find_elements(By.NAME, action)
            found_action_cell = False
            for action_el in action_cells:
                if action_el.rect['y'] == row_y:
                    found_action_cell = True
                    break
            if not found_action_cell:
                raise NoSuchElementException(
                    f'Activity for "{resource}" does not have "{action}" action'
                )
            account_cells = app().find_elements(By.NAME, account)
            found_account_cell = False
            for account_el in account_cells:
                if account_el.rect['y'] == row_y:
                    found_account_cell = True
                    break
            if not found_account_cell:
                raise NoSuchElementException(
                    f'Activity for "{resource}" does not have "{account}" account label'
                )
            return True
        except:
            return False

    @staticmethod
    def select_not_synced_filter(filter_option):
        squish.clickButton(squish.waitForObject(Activity.NOT_SYNCED_FILTER_BUTTON))
        squish.activateItem(
            squish.waitForObjectItem(
                Activity.NOT_SYNCED_FILTER_OPTION_SELECTOR, filter_option
            )
        )

    @staticmethod
    def get_not_synced_table_column_number_by_name(column_name):
        return squish.waitForObject(
            {
                "container": Activity.NOT_SYNCED_ACTIVITY_TABLE_HEADER_SELECTOR,
                "text": column_name,
                "type": "HeaderViewItem",
                "visible": True,
            }
        )["section"]

    @staticmethod
    def check_not_synced_table(resource, status, account):
        try:
            file_row = squish.waitForObject(
                Activity.get_not_synced_file_selector(resource),
                get_config("lowestSyncTimeout") * 1000,
            )["row"]
            squish.waitForObjectExists(
                {
                    "column": Activity.get_not_synced_table_column_number_by_name(
                        "Status"
                    ),
                    "row": file_row,
                    "container": Activity.NOT_SYNCED_TABLE,
                    "text": status,
                    "type": "QModelIndex",
                }
            )
            squish.waitForObjectExists(
                {
                    "column": Activity.get_not_synced_table_column_number_by_name(
                        "Account"
                    ),
                    "row": file_row,
                    "container": Activity.NOT_SYNCED_TABLE,
                    "text": account,
                    "type": "QModelIndex",
                }
            )
            return True
        except:
            return False
