# coding: utf-8
"""
Course Schedule and Details Settings page.
"""
from __future__ import unicode_literals
import os
from bok_choy.promise import EmptyPromise
from bok_choy.javascript import requirejs

from common.test.acceptance.pages.studio.course_page import CoursePage
from common.test.acceptance.pages.studio.users import wait_for_ajax_or_reload
from common.test.acceptance.pages.studio.utils import (
    press_the_notification_button,
    type_in_codemirror
)


@requirejs('js/factories/settings')
class SettingsPage(CoursePage):
    """
    Course Schedule and Details Settings page.
    """

    url_path = "settings/details"
    upload_image_browse_button_selector = 'form.upload-dialog input[type=file]'
    upload_image_upload_button_selector = '.modal-actions li:nth-child(1) a'
    upload_image_popup_window_selector = '.assetupload-modal'

    ################
    # Helpers
    ################
    def is_browser_on_page(self):
        wait_for_ajax_or_reload(self.browser)
        return self.q(css='body.view-settings').visible

    def wait_for_require_js(self):
        """
        Wait for require-js to load javascript files.
        """
        if hasattr(self, 'wait_for_js'):
            self.wait_for_js()  # pylint: disable=no-member

    def wait_for_jquery_value(self, jquery_element, value):
        """
        Use jQuery to obtain the element's value.
        This is useful for when jQuery performs functions towards the
        end of the page load. (In other words, waiting for jquery to
        load is not enough; we need to also query values that it has
        injected onto the page to ensure it's done.)
        """
        self.wait_for(
            lambda: self.browser.execute_script(
                "return $('{ele}').val();".format(ele=jquery_element)) == '{val}'.format(val=value),
            'wait for jQuery to finish loading data on page.'
        )

    def refresh_and_wait_for_load(self):
        """
        Refresh the page and wait for all resources to load.
        """
        self.browser.refresh()
        self.wait_for_page()

    def get_elements(self, css_selector):
        self.wait_for_element_presence(
            css_selector,
            'Elements matching "{}" selector are present'.format(css_selector)
        )
        results = self.q(css=css_selector)
        return results

    def get_element(self, css_selector):
        results = self.get_elements(css_selector=css_selector)
        return results[0] if results else None

    def set_element_values(self, element_values):
        """
        Set the values of the elements to those specified
        in the element_values dict.
        """
        for css, value in element_values.iteritems():
            element = self.get_element(css)
            element.clear()
            element.send_keys(value)

    def un_focus_input_field(self):
        """
        Makes an input field un-focus by
        clicking outside of it.
        """
        self.get_element('.title-2').click()

    def is_element_present(self, css_selector):
        """
        Returns boolean based on the presence
        of an element with css as passed.
        """
        return self.q(css=css_selector).present

    def change_course_description(self, change_text):
        """
        Changes the course description
        """
        type_in_codemirror(self, 0, change_text, find_prefix="$")

    ################
    # Properties
    ################
    @property
    def pre_requisite_course_options(self):
        """
        Returns the pre-requisite course drop down field options.
        """
        self.wait_for_element_visibility(
            '#pre-requisite-course',
            'Prerequisite course element is available'
        )
        return self.get_elements('#pre-requisite-course')

    @property
    def entrance_exam_field(self):
        """
        Returns the enable entrance exam checkbox.
        """
        self.wait_for_element_visibility(
            '#entrance-exam-enabled',
            'Entrance exam checkbox is available'
        )
        return self.get_element('#entrance-exam-enabled')

    @property
    def alert_confirmation_title(self):
        """
        Returns the alert confirmation element, which contains text
        such as 'Your changes have been saved.'
        """
        self.wait_for_element_visibility(
            '#alert-confirmation-title',
            'Alert confirmation title element is available'
        )
        return self.get_element('#alert-confirmation-title')

    @property
    def course_license(self):
        """
        Property. Returns the text of the license type for the course
        ("All Rights Reserved" or "Creative Commons")
        """
        license_types_css = ".license ul.license-types li.license-type"
        self.wait_for_element_presence(
            license_types_css,
            "license type buttons are present",
        )
        selected = self.q(css=license_types_css + " button.is-selected")
        if selected.is_present():
            return selected.text[0]

        # Look for the license text that will be displayed by default,
        # if no button is yet explicitly selected
        license_text = self.q(css='.license span.license-text')
        if license_text.is_present():
            return license_text.text[0]
        return None

    @course_license.setter
    def course_license(self, license_name):
        """
        Sets the course license to the given license_name
        (str, "All Rights Reserved" or "Creative Commons")
        """
        license_types_css = ".license ul.license-types li.license-type"
        self.wait_for_element_presence(
            license_types_css,
            "license type buttons are present",
        )
        button_xpath = (
            "//div[contains(@class, 'license')]"
            "//ul[contains(@class, 'license-types')]"
            "//li[contains(@class, 'license-type')]"
            "//button[contains(text(),'{license_name}')]"
        ).format(license_name=license_name)
        button = self.q(xpath=button_xpath)
        if not button.present:
            raise Exception("Invalid license name: {name}".format(name=license_name))
        button.click()

    pacing_css = '.pacing input[type=radio]'

    @property
    def checked_pacing_css(self):
        """CSS for the course pacing button which is currently checked."""
        return self.pacing_css + ':checked'

    @property
    def course_pacing(self):
        """
        Returns the label text corresponding to the checked pacing radio button.
        """
        self.wait_for_element_presence(self.checked_pacing_css, 'course pacing controls present and rendered')
        checked = self.q(css=self.checked_pacing_css).results[0]
        checked_id = checked.get_attribute('id')
        return self.q(css='label[for={checked_id}]'.format(checked_id=checked_id)).results[0].text

    @course_pacing.setter
    def course_pacing(self, pacing):
        """
        Sets the course to either self-paced or instructor-paced by checking
        the appropriate radio button.
        """
        self.wait_for_element_presence(self.checked_pacing_css, 'course pacing controls present')
        self.q(xpath="//label[contains(text(), '{pacing}')]".format(pacing=pacing)).click()

    @property
    def course_pacing_disabled_text(self):
        """
        Return the message indicating that course pacing cannot be toggled.
        """
        return self.q(css='#course-pace-toggle-tip').results[0].text

    def course_pacing_disabled(self):
        """
        Return True if the course pacing controls are disabled; False otherwise.
        """
        self.wait_for_element_presence(self.checked_pacing_css, 'course pacing controls present')
        statuses = self.q(css=self.pacing_css).map(lambda e: e.get_attribute('disabled')).results
        return all((s == 'true' for s in statuses))

    ################
    # Waits
    ################
    def wait_for_prerequisite_course_options(self):
        """
        Ensure the pre_requisite_course_options dropdown selector is displayed
        """
        EmptyPromise(
            lambda: self.q(css="#pre-requisite-course").present,
            'Prerequisite course dropdown selector is displayed'
        ).fulfill()

    ################
    # Clicks
    ################

    def click_button(self, name):
        """
        Clicks the button
        """
        btn_css = 'div#page-notification button.action-{}'.format(name.lower())
        EmptyPromise(
            lambda: self.q(css=btn_css).visible,
            '{} button is visible'.format(name)
        ).fulfill()
        press_the_notification_button(self, name)

    ################
    # Workflows
    ################

    def require_entrance_exam(self, required=True):
        """
        Set the entrance exam requirement via the checkbox.
        """
        checkbox = self.entrance_exam_field
        selected = checkbox.is_selected()
        if required and not selected:
            checkbox.click()
            self.wait_for_element_visibility(
                '#entrance-exam-minimum-score-pct',
                'Entrance exam minimum score percent is visible'
            )
        if not required and selected:
            checkbox.click()
            self.wait_for_element_invisibility(
                '#entrance-exam-minimum-score-pct',
                'Entrance exam minimum score percent is invisible'
            )

    def save_changes(self, wait_for_confirmation=True):
        """
        Clicks save button, waits for confirmation unless otherwise specified
        """
        press_the_notification_button(self, "save")
        if wait_for_confirmation:
            self.wait_for_element_visibility(
                '#alert-confirmation-title',
                'Save confirmation message is visible'
            )

    def refresh_page(self, wait_for_confirmation=True):
        """
        Reload the page.
        """
        self.browser.refresh()
        if wait_for_confirmation:
            EmptyPromise(
                lambda: self.q(css='body.view-settings').present,
                'Page is refreshed'
            ).fulfill()
        self.wait_for_require_js()
        self.wait_for_ajax()

    @staticmethod
    def get_asset_path(file_name):
        """
        Returns the full path of the file to upload.
        These files have been placed in edx-platform/common/test/data/uploads/
        """

        # Separate the list of folders in the path reaching to the current file,
        # e.g.  '... common/test/acceptance/pages/lms/instructor_dashboard.py' will result in
        #       [..., 'common', 'test', 'acceptance', 'pages', 'lms', 'instructor_dashboard.py']
        folders_list_in_path = __file__.split(os.sep)

        # Get rid of the last 4 elements: 'acceptance', 'pages', 'lms', and 'instructor_dashboard.py'
        # to point to the 'test' folder, a shared point in the path's tree.
        folders_list_in_path = folders_list_in_path[:-4]

        # Append the folders in the asset's path
        folders_list_in_path.extend(['data', 'uploads', file_name])

        # Return the joined path of the required asset.
        return os.sep.join(folders_list_in_path)

    def upload_image(self, upload_btn_selector, file_to_upload):
        """
        Upload image specified by image_selector and file_to_upload
        """

        # wait for upload button
        self.wait_for_element_visibility(upload_btn_selector, 'upload button is present')

        self.q(css=upload_btn_selector).results[0].click()

        # wait for popup
        self.wait_for_element_presence(self.upload_image_popup_window_selector, 'upload dialog is present')

        # upload image
        filepath = SettingsPage.get_asset_path(file_to_upload)
        self.q(css=self.upload_image_browse_button_selector).results[0].send_keys(filepath)
        self.q(css=self.upload_image_upload_button_selector).results[0].click()

        # wait for popup closed
        self.wait_for_element_absence(self.upload_image_popup_window_selector, 'upload dialog is hidden')

    def get_uploaded_image_path(self, image_selector):
        """
        Returns the uploaded image path
        """

        return self.q(css=image_selector).attrs('src')[0]
