# -*- coding: utf-8 -*-
"""
End-to-end tests for t
he Account Settings page.
"""
from unittest import skip
from nose.plugins.attrib impo
rt attr

from bok_choy.web_app_test import WebAppTest

from ...pages.lms.account_settings import AccountSettingsPage
from ...pages.lms.auto_auth import AutoAuthPage
from ...pages.lms.dashboard import DashboardPage

from ..helpers import EventsTestMixin


class AccountSettingsTestMixin(EventsTestMixin, WebAppTest):
    """
    Mixin with helper methods to test the account settings page.
    """

    CHANGE_INITIATED_EVENT_NAME = u"edx.user.settings.change_initiated"
    USER_SETTINGS_CHANGED_EVENT_NAME = 'edx.user.settings.changed'
    ACCOUNT_SETTINGS_REFERER = u"/account/settings"

    def visit_account_settings_page(self):
        """
        Visit the account settings page for the current user, and store the page instance
        as self.account_settings_page.
        """
        # pylint: disable=attribute-defined-outside-init
        self.account_settings_page = AccountSettingsPage(self.browser)
        self.account_settings_page.visit()
        self.account_settings_page.wait_for_ajax()

    def log_in_as_unique_user(self, email=None):
        """
        Create a unique user and return the account's username and id.
        """
        username = "test_{uuid}".format(uuid=self.unique_id[0:6])
        auto_auth_page = AutoAuthPage(self.browser, username=username, email=email).visit()
        user_id = auto_auth_page.get_user_id()
        return username, user_id

    def settings_changed_event_filter(self, event):
        """Filter out any events that are not "settings changed" events."""
        return event['event_type'] == self.USER_SETTINGS_CHANGED_EVENT_NAME

    def expected_settings_changed_event(self, setting, old, new, table=None):
        """A dictionary representing the expected fields in a "settings changed" event."""
        return {
            'username': self.username,
            'referer': self.get_settings_page_url(),
            'event': {
                'user_id': self.user_id,
                'setting': setting,
                'old': old,
                'new': new,
                'truncated': [],
                'table': table or 'auth_userprofile'
            }
        }

    def settings_change_initiated_event_filter(self, event):
        """Filter out any events that are not "settings change initiated" events."""
        return event['event_type'] == self.CHANGE_INITIATED_EVENT_NAME

    def expected_settings_change_initiated_event(self, setting, old, new, username=None, user_id=None):
        """A dictionary representing the expected fields in a "settings change initiated" event."""
        return {
            'username': username or self.username,
            'referer': self.get_settings_page_url(),
            'event': {
                'user_id': user_id or self.user_id,
                'setting': setting,
                'old': old,
                'new': new,
            }
        }

    def get_settings_page_url(self):
        """The absolute URL of the account settings page given the test context."""
        return self.relative_path_to_absolute_uri(self.ACCOUNT_SETTINGS_REFERER)

    def assert_no_setting_changed_event(self):
        """Assert no setting changed event has been emitted thus far."""
        self.assert_no_matching_events_were_emitted({'event_type': self.USER_SETTINGS_CHANGED_EVENT_NAME})


@attr('shard_8')
class DashboardMenuTest(AccountSettingsTestMixin, WebAppTest):
    """
    Tests that the dashboard menu works correctly with the account settings page.
    """
    def test_link_on_dashboard_works(self):
        """
        Scenario: Verify that the "Account" link works from the dashboard.


        Given that I am a registered user
        And I visit my dashboard
        And I click on "Account" in the top drop down
        Then I should see my account settings page
        """
        self.log_in_as_unique_user()
        dashboard_page = DashboardPage(self.browser)
        dashboard_page.visit()
        dashboard_page.click_username_dropdown()
        self.assertIn('Account', dashboard_page.username_dropdown_link_text)
        dashboard_page.click_account_settings_link()


@attr('shard_8')
class AccountSettingsPageTest(AccountSettingsTestMixin, WebAppTest):
    """
    Tests that verify behaviour of the Account Settings page.
    """
    SUCCESS_MESSAGE = 'Your changes have been saved.'

    def setUp(self):
        """
        Initialize account and pages.
        """
        super(AccountSettingsPageTest, self).setUp()
        self.username, self.user_id = self.log_in_as_unique_user()
        self.visit_account_settings_page()

    def test_page_view_event(self):
        """
        Scenario: An event should be recorded when the "Account Settings"
           page is viewed.

        Given that I am a registered user
        And I visit my account settings page
        Then a page view analytics event should be recorded
        """

        actual_events = self.wait_for_events(
            event_filter={'event_type': 'edx.user.settings.viewed'}, number_of_matches=1)
        self.assert_events_match(
            [
                {
                    'event': {
                        'user_id': self.user_id,
                        'page': 'account',
                        'visibility': None
                    }
                }
            ],
            actual_events
        )

    def test_all_sections_and_fields_are_present(self):
        """
        Scenario: Verify that all sections and fields are present on the page.
        """
        expected_sections_structure = [
            {
                'title': 'Basic Account Information (required)',
                'fields': [
                    'Username',
                    'Full Name',
                    'Email Address',
                    'Password',
                    'Language',
                    'Country or Region'
                ]
            },
            {
                'title': 'Additional Information (optional)',
                'fields': [
                    'Education Completed',
                    'Gender',
                    'Year of Birth',
                    'Preferred Language',
                ]
            },
            {
                'title': 'Connected Accounts',
                'fields': [
                    'Dummy',
                    'Facebook',
                    'Google',
                ]
            }
        ]

        self.assertEqual(self.account_settings_page.sections_structure(), expected_sections_structure)

    def _test_readonly_field(self, field_id, title, value):
        """
        Test behavior of a readonly field.
        """
        self.assertEqual(self.account_settings_page.title_for_field(field_id), title)
        self.assertEqual(self.account_settings_page.value_for_readonly_field(field_id), value)

    def _test_text_field(
            self, field_id, title, initial_value, new_invalid_value, new_valid_values, success_message=SUCCESS_MESSAGE,
            assert_after_reload=True
    ):
        """
        Test behaviour of a text field.
        """
        self.assertEqual(self.account_settings_page.title_for_field(field_id), title)
        self.assertEqual(self.account_settings_page.value_for_text_field(field_id), initial_value)

        self.assertEqual(
            self.account_settings_page.value_for_text_field(field_id, new_invalid_value), new_invalid_value
        )
        self.account_settings_page.wait_for_indicator(field_id, 'validation-error')
        self.browser.refresh()
        self.assertNotEqual(self.account_settings_page.value_for_text_field(field_id), new_invalid_value)

        for new_value in new_valid_values:
            self.assertEqual(self.account_settings_page.value_for_text_field(field_id, new_value), new_value)
            self.account_settings_page.wait_for_message(field_id, success_message)
            if assert_after_reload:
                self.browser.refresh()
                self.assertEqual(self.account_settings_page.value_for_text_field(field_id), new_value)

    