import common
import subprocess
import time

from lib_python import execution, logger, steps, variables
from lib_python.baseObjects.AppiumObject import AppiumObject

from libcrashtest.InputParameterConvertor import InputParameterConvertor

# default runtime config values
_skip_waiting = InputParameterConvertor.convert_to_bool(common.runtime_config["skip_waiting"]) if "skip_waiting" in common.runtime_config else False


def check_current_activity(params):
    expected_activity = params["activity"]

    wait_time = 1 if _skip_waiting else 60  # seconds
    elapsed_time = 0  # seconds

    found_activity = None

    while elapsed_time < wait_time:
        found_activity = variables.driver.current_activity

        if expected_activity == found_activity:
            logger.debug("Successfully found activity: {0}".format(found_activity))
            execution.passed()
            return

        # sleep for one second
        logger.debug("Activity not found yet, sleeping for 1 second")
        time.sleep(1)
        elapsed_time += 1

    execution.error("Expected {0} activity, but found {1} instead.".format(expected_activity, found_activity))

steps.new_step("Common - Check that current activity is {activity}", check_current_activity)


def check_current_activity_is_not_app(params):
    not_expected_activity_prefix = params["activity_prefix"]
    found_activity = variables.driver.current_activity

    if found_activity is not None and found_activity.startswith(not_expected_activity_prefix):
        execution.error("Current activity should not start with {0}, but found {1} instead.".format(not_expected_activity_prefix, found_activity))

    execution.passed()

steps.new_step("Common - Check that current activity does not start with {activity_prefix}", check_current_activity_is_not_app)


def pull_notification_bar(params):
    direction = params["direction"]

    if direction == "up":
        variables.driver.press_keycode(4)  # BACK button
    elif direction == "down":
        variables.driver.open_notifications()
    else:
        execution.error("Invalid direction: {0}".format(direction))

    execution.passed()

steps.new_step("Common - Pull notification bar {direction}", pull_notification_bar)


def find_first_notification():
    notification_title = AppiumObject(variables.driver, "android:id/title")
    notification_title.wait_for(60)
    notification_title_y = notification_title.get_location()['y']
    found_title = notification_title.get_text()

    notification_message = AppiumObject(variables.driver, "android:id/big_text")
    notification_message.wait_for(60)
    notification_message_y = notification_message.get_location()['y']
    found_message = notification_message.get_text()

    variables.notification_y = (notification_title_y + notification_message_y) / 2
    variables.notification_title = found_title
    variables.notification_message = found_message

    execution.passed()

steps.new_step("Common - Find first notification", find_first_notification)


def check_notification(params):
    expected_title = params["title"]
    expected_message = params["message"]

    notification_title = AppiumObject(variables.driver, "android:id/title")
    notification_title.wait_for(30)
    notification_title_y = notification_title.get_location()['y']
    found_title = notification_title.get_text()

    notification_message = AppiumObject(variables.driver, "android:id/text")
    notification_message.wait_for(30)
    notification_message_y = notification_message.get_location()['y']
    found_message = notification_message.get_text()

    variables.notification_y = (notification_title_y + notification_message_y) / 2
    variables.notification_title = found_title
    variables.notification_message = found_message

    if expected_title != found_title:
        execution.error("Expected dialog title: {0}, but found {1} instead.".format(expected_title, found_title))

    if expected_message != found_message:
        execution.error("Expected dialog message: {0}, but found {1} instead.".format(expected_message, found_message))

    execution.passed()

steps.new_step("Common - Check notification with title: {title} and message: {message}", check_notification)


def dismiss_notification():
    horizontal_center = variables.driver.get_window_size()["width"] / 2
    variables.driver.swipe(horizontal_center, variables.notification_y, 1, variables.notification_y)

    notification_title = None
    notification_message = None

    # noinspection PyBroadException
    try:
        notification_title = AppiumObject(variables.driver, "android:id/title").get_text()
        notification_message = AppiumObject(variables.driver, "android:id/text").get_text()
    except:
        # no more notifications
        execution.passed()

    if notification_title == variables.notification_title or notification_message == variables.notification_message:
        execution.error("Notification not dismissed.")

    execution.passed()

steps.new_step("Common - Dismiss notification", dismiss_notification)


def reset_driver():
    variables.driver.close_app()
    variables.driver.launch_app()
    execution.passed()

steps.new_step("Common - Restart application", reset_driver)


def clear_crash_directory():
    try:
        subprocess.check_call("adb shell rm /sdcard/Android/data/com.avg.zaap.crash/files/*", shell=True)
    except subprocess.CalledProcessError:
        execution.error("Cannot perform clearing of the crash directory.")

    execution.passed()

steps.new_step("Common - Clear crash directory", clear_crash_directory)


def check_crash_file_exists(params):
    file_ = params["file"]

    timeout = 1 if _skip_waiting else 60 # seconds
    elapsed_time = 0  # seconds

    while elapsed_time < timeout:
        result = subprocess.check_output("adb shell ls /sdcard/Android/data/com.avg.zaap.crash/files/{0}".format(file_),
                                         shell=True)
        result = result.split("\r\r\n")

        try:
            result.index("/sdcard/Android/data/com.avg.zaap.crash/files/{0}".format(file_))
            execution.passed()
            return
        except ValueError:
            # wait one second
            logger.debug("Crash file not found. Waiting one second.")
            time.sleep(1)
            elapsed_time += 1

    execution.error("Crash file {0} does not exist.".format(file_))

steps.new_step("Common - Check that crash file {file} exists", check_crash_file_exists)


def check_native_crash_file_exists():
    result = subprocess.check_output("adb shell ls /sdcard/Android/data/com.avg.zaap.crash/files/*-*-*-*-*", shell=True)
    result.split("\r\r\n")
    result = filter(lambda x: len(x) != 0, result)

    if len(result) == 0:
        execution.error("Native crash file not found.")

    execution.passed()

steps.new_step("Common - Check native crash file exists", check_native_crash_file_exists)


def dismiss_dialog():
    dismiss_button = AppiumObject(variables.driver, "android:id/button1")
    dismiss_button.wait_for(15)
    dismiss_button.click()
    execution.passed()

steps.new_step("Common - Dismiss dialog", dismiss_dialog)


def check_element_not_visible(params):
    element = AppiumObject(variables.driver, params["id"])
    try:
        element.get_element()
        execution.error("Element should be invisible but found on the current screen")
    except LookupError:
        logger.debug("Element not visible.")
        execution.passed()

steps.new_step("Common - Check that element with id {id} is not visible", check_element_not_visible)
