"""Other pages associated with Fitbit Companion App testing."""
import shlex

from typing import List, Optional
from xml.dom import minidom

from blueberry.utils.ui_pages import errors
from blueberry.utils.ui_pages import ui_core
from blueberry.utils.ui_pages import ui_node
from blueberry.utils.ui_pages.fitbit_companion import constants

# Typing hint alias.
NodeList = List[ui_node.UINode]


class LoginInputPage(ui_core.UIPage):
    """Fitbit Companion App's login input page."""

    PAGE_TEXT = 'Forgot password?'
    _NODE_EMAIL_INPUT_TEXT = f'{constants.PKG_NAME_ID}/login_email'
    _NODE_PASSWORD_INPUT_RID = f'{constants.PKG_NAME_ID}/login_password'
    _NODE_LOGIN_BUTTON_RID = f'{constants.PKG_NAME_ID}/login_button'

    def input(self, account: str, password: str) -> ui_core.UIPage:
        """Inputs login credentials.

    Args:
      account: The account is used to login Fitbit App.
      password: The password is used to login Fitbit App.

    Returns:
      The transformed page.
    """
        self.click_node_by_rid(self._NODE_EMAIL_INPUT_TEXT)
        self.ctx.ad.adb.shell(shlex.split(f'input text "{account}"'))
        self.click_node_by_rid(self._NODE_PASSWORD_INPUT_RID)
        self.ctx.ad.adb.shell(shlex.split(f'input text "{password}"'))
        return self.click_node_by_rid(self._NODE_LOGIN_BUTTON_RID)


class GoogleSmartLockSavePage(ui_core.UIPage):
    """Google SmartLock popup to save input credentials."""

    PAGE_TEXT = 'Save password to Google?'
    _NODE_NO_RID = 'android:id/autofill_save_no'
    _NODE_YES_RID = 'android:id/autofill_save_yes'

    def yes(self) -> ui_core.UIPage:
        """Saves the input credentials in Google SmartLock.

    Returns:
      The transformed page.
    """
        return self.click_node_by_rid(self._NODE_YES_RID)

    def no(self) -> ui_core.UIPage:
        """Skips the request to save input credentials.

    Returns:
      The transformed page.
    """
        return self.click_node_by_rid(self._NODE_NO_RID)


class GoogleSmartLockPage(ui_core.UIPage):
    """Google SmartLock popup from login page."""

    PAGE_TEXT = 'Google Smartlock'
    _NODE_YES_TEXT = 'YES'
    _NODE_NO_TEXT = 'NO'

    def yes(self) -> ui_core.UIPage:
        """Logins by GoogleSmartLock.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_YES_TEXT)

    def no(self) -> ui_core.UIPage:
        """Skips GoogleSmartLock.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_NO_TEXT)


class LoginPage(ui_core.UIPage):
    """Fitbit Companion App's login page."""

    PAGE_TEXT = 'Log in'

    def login(self,
              account: str,
              password: str,
              allow_google_smartlock: bool = True) -> ui_core.UIPage:
        """Logins the Fitbit Companion App.

    Args:
      account: Login account
      password: Login password
      allow_google_smartlock: True to allow Google SmartLock feature.

    Returns:
      The transformed page.
    """
        self.click_node_by_text(self.PAGE_TEXT)
        self.ctx.expect_pages([GoogleSmartLockPage, LoginInputPage])
        if self.ctx.is_page(GoogleSmartLockPage):
            if allow_google_smartlock:
                return self.ctx.page.yes()
            else:
                self.ctx.page.no()

        self.ctx.expect_page(LoginInputPage)
        return self.ctx.page.input(account, password)


class GooglePlayPage(ui_core.UIPage):
    """Fitbit Companion App's GooglePlay page."""

    _FITBIT_COMPANION_NAME_TEXT = 'Fitbit, Inc.'
    _NODE_RESOURCE_NAME_RID = 'com.android.vending:id/0_resource_name_obfuscated'
    _NODE_UNINSTALL_BUTTON_TEXT = 'Uninstall'
    _NODE_OPEN_BUTTON_TEXT = 'Open'
    _NODE_INSTALL_BUTTON_TEXT = 'Install'

    @classmethod
    def from_xml(cls, ctx: ui_core.Context, ui_xml: minidom.Document, clickable_nodes: NodeList,
                 enabled_nodes: NodeList, all_nodes: NodeList) -> Optional[ui_core.UIPage]:
        """Instantiates page object from XML object.

    Args:
      ctx: Page context object.
      ui_xml: Parsed XML object.
      clickable_nodes: Clickable node list from page.
      enabled_nodes: Enabled node list from page.
      all_nodes: All node from page.

    Returns:
      UI page object iff the given XML object can be parsed.
    """
        for node in enabled_nodes:
            if (node.text == cls._FITBIT_COMPANION_NAME_TEXT and
                    node.resource_id == cls._NODE_RESOURCE_NAME_RID):
                return cls(ctx, ui_xml, clickable_nodes, enabled_nodes, all_nodes)

    def open(self) -> ui_core.UIPage:
        """Opens the Fitbit Companion App.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_OPEN_BUTTON_TEXT)

    def install(self, open_app: bool = True) -> ui_core.UIPage:
        """Installs the Fitbit Companion App.

    Args:
      open_app: True to open application after installation.

    Returns:
      The transformed page.
    """
        if self.get_node_by_text(self._NODE_OPEN_BUTTON_TEXT) is None:
            # The app is not installed yet.
            self.click_node_by_text(self._NODE_INSTALL_BUTTON_TEXT)
            self.ctx.expect_page(self.__class__,
                                 wait_sec=120,
                                 node_eval=lambda node: node.text == self._NODE_OPEN_BUTTON_TEXT)

        if open_app:
            return self.ctx.page.open()
        else:
            return self.ctx.page


class AllowLocationPermissionConfirmPopup(ui_core.UIPage):
    """Page to confirm the location permission request."""

    PAGE_RE_TEXT = 'This app wants to access your location'
    _ALLOW_BUTTON_RESOURCE_ID = 'com.android.permissioncontroller:id/permission_no_upgrade_button'

    def allow(self) -> ui_core.UIPage:
        """Allows the request."""
        return self.click_node_by_rid(self._ALLOW_BUTTON_RESOURCE_ID)


class AllowLocationPermissionPopup(ui_core.UIPage):
    """Page to allow location permission."""

    PAGE_TEXT = 'While using the app'

    def next(self) -> ui_core.UIPage:
        """Allows the permission."""
        return self.click_node_by_text(self.PAGE_TEXT)


class LocationPermissionSync(ui_core.UIPage):
    """Page to require location permission required by Fitbit Companion App."""

    PAGE_TEXT = 'Location permission required to sync'
    _EXIT_IMAGE_CLASS = 'android.widget.ImageButton'
    _LOCATION_PERMISSION_CHECK_BOX_TEXT = 'Location Permission'
    _UPDATE_BUTTON_TEXT = 'Update Settings'

    def enable(self) -> ui_core.UIPage:
        """Enables location permission to app."""
        self.ctx.enable_registered_page_call = False
        self.click_node_by_text(self._LOCATION_PERMISSION_CHECK_BOX_TEXT)
        self.ctx.get_page()
        self.ctx.expect_page(AllowLocationPermissionPopup)
        self.ctx.page.next()
        self.ctx.expect_page(AllowLocationPermissionConfirmPopup)
        self.ctx.page.allow()
        self.click_node_by_text(self._UPDATE_BUTTON_TEXT)
        self.ctx.enable_registered_page_call = True
        return self.click_node_by_class(self._EXIT_IMAGE_CLASS)


class PurchaseFail(ui_core.UIPage):
    """Fitbit Companion App's page to show failure of purchase."""

    PAGE_TEXT = 'Purchase failed!'
    _NODE_OK_TEXT = 'OK'

    def ok(self) -> ui_core.UIPage:
        """Confirms the failure.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_OK_TEXT)


class AllowNotification(ui_core.UIPage):
    """Fitbit Companion App's page to allow access of notification."""

    PAGE_TEXT = 'Allow notification access for Fitbit?'
    _NODE_ALLOW_TEXT = 'Allow'
    _NODE_DENY_TEXT = 'Deny'

    def allow(self) -> ui_core.UIPage:
        """Allows the request.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_ALLOW_TEXT)

    def deny(self) -> ui_core.UIPage:
        """Denies the request.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_DENY_TEXT)


class SettingLocation(ui_core.UIPage):
    """Android location setting page."""

    _NODE_SWITCH_RID = 'com.android.settings:id/switch_widget'
    _NODE_SWITCH_TEXT_RID = 'com.android.settings:id/switch_text'

    @classmethod
    def from_xml(cls, ctx: ui_core.Context, ui_xml: minidom.Document, clickable_nodes: NodeList,
                 enabled_nodes: NodeList, all_nodes: NodeList) -> Optional[ui_core.UIPage]:
        """Instantiates page object from XML object.

    Args:
      ctx: Page context object.
      ui_xml: Parsed XML object.
      clickable_nodes: Clickable node list from page.
      enabled_nodes: Enabled node list from page.
      all_nodes: All node from page.

    Returns:
      UI page object iff the given XML object can be parsed.
    """
        for node in enabled_nodes:
            if (node.text == 'Use location' and node.resource_id == cls._NODE_SWITCH_TEXT_RID):
                return cls(ctx, ui_xml, clickable_nodes, enabled_nodes, all_nodes)

    def back(self) -> ui_core.UIPage:
        """Backs to previous page.

    Returns:
      The transformed page.
    """
        self.click_node_by_content_desc('Navigate up')
        return self.swipe_left()

    @property
    def enabled(self) -> bool:
        """Checks the location setting.

    Returns:
      True iff the location is enabled.

    Raises:
      errors.UIError: Fail to find the target node.
    """
        node = self.get_node_by_rid(self._NODE_SWITCH_RID)
        if not node:
            raise errors.UIError('Fail to get switch node!')

        return node.attributes['checked'].value == 'true'

    def set(self, value: bool) -> ui_core.UIPage:
        """Toggles the switch to enable/disable location.

    Args:
      value: True to turn on setting; False to turn off setting.

    Returns:
      The transformed page.
    """
        if value != self.enabled:
            return self.click_node_by_rid(self._NODE_SWITCH_RID)

        return self


class LocationDisabledPage(ui_core.UIPage):
    """Popup page for notification as location is disabled."""

    PAGE_RE_TEXT = 'ENABLE LOCATIONS'
    _NODE_ENABLE_TEXT = 'ENABLE LOCATIONS'

    def enable(self) -> ui_core.UIPage:
        """Enables the location setting.

    Returns:
      The transformed page.
    """
        return self.click_node_by_text(self._NODE_ENABLE_TEXT)


class LinkConfirmPage(ui_core.UIPage):
    """Popup page to confirm the process of pairing."""

    PAGE_RID = 'com.android.companiondevicemanager:id/buttons'
    _NODE_PAIR_BTN_RID = 'com.android.companiondevicemanager:id/button_pair'

    def ok(self) -> ui_core.UIPage:
        """Confirms pairing process.

    Returns:
      The transformed page.
    """
        return self.click_node_by_rid(self._NODE_PAIR_BTN_RID)
