# pylint: disable=missing-docstring
# pylint: disable=redefined-outer-name

from __future__ import absolute_import

import time
from logging import getLogger

from django.contrib.auth.models import User
from django.core.urlresolvers import reverse
from lettuce import before, step, world
from lettuce.django import django_url

from courseware.courses import get_course_by_id
from student.models import CourseEnrollment
from xmodule import seq_module, vertical_block
from xmodule.course_module import CourseDescriptor
from xmodule.modulestore.django import modulestore

logger = getLogger(__name__)


@step('I (.*) capturing of screenshots before and after each step$')
def configure_screenshots_for_all_steps(_step, action):
    """
    A step to be used in *.feature files. Enables/disables
    automatic saving of screenshots before and after each step in a
    scenario.
    """
    action = action.strip()
    if action == 'enable':
        world.auto_capture_screenshots = True
    elif action == 'disable':
        world.auto_capture_screenshots = False
    else:
        raise ValueError('Parameter `action` should be one of "enable" or "disable".')


@world.absorb
def capture_screenshot_before_after(func):
    """
    A decorator that will take a screenshot before and after the applied
    function is run. Use this if you do not want to capture screenshots
    for each step in a scenario, but rather want to debug a single function.
    """
    def inner(*args, **kwargs):
        prefix = round(time.time() * 1000)

        world.capture_screenshot("{}_{}_{}".format(
            prefix, func.func_name, 'before'
        ))
        ret_val = func(*args, **kwargs)
        world.capture_screenshot("{}_{}_{}".format(
            prefix, func.func_name, 'after'
        ))
        return ret_val
    return inner


@step(u'The course "([^"]*)" exists$')
def create_course(_step, course):

    # First clear the modulestore so we don't try to recreate
    # the same course twice
    # This also ensures that the necessary templates are loaded
    world.clear_courses()

    # Create the course
    # We always use the same org and display name,
    # but vary the course identifier (e.g. 600x or 191x)
    world.scenario_dict['COURSE'] = world.CourseFactory.create(
        org='edx',
        number=course,
        display_name='Test Course'
    )

    # Add a chapter to the course to contain problems
    world.scenario_dict['CHAPTER'] = world.ItemFactory.create(
        parent_location=world.scenario_dict['COURSE'].location,
        category='chapter',
        display_name='Test Chapter',
        publish_item=True,  # Not needed for direct-only but I'd rather the test didn't know that
    )

    world.scenario_dict['SECTION'] = world.ItemFactory.create(
        parent_location=world.scenario_dict['CHAPTER'].location,
        category='sequential',
        display_name='Test Section',
        publish_item=True,
    )


@step(u'I am registered for the course "([^"]*)"$')
def i_am_registered_for_the_course(step, course):
    # Create the course
    create_course(step, course)

    # Create the user
    world.create_user('robot', 'test')
    user = User.objects.get(username='robot')

    # If the user is not already enrolled, enroll the user.
    # TODO: change to factory
    CourseEnrollment.enroll(user, course_id(course))

    world.log_in(username='robot', password='test')


@step(u'The course "([^"]*)" has extra tab "([^"]*)"$')
def add_tab_to_course(_step, course, extra_tab_name):
    world.ItemFactory.create(
        parent_location=course_location(course),
        category="static_tab",
        display_name=str(extra_tab_name))


@step(u'I am in a course$')
def go_into_course(step):
    step.given('I am registered for the course "6.002x"')
    step.given('And I am logged in')
    step.given('And I click on View Courseware')


# Do we really use these 3 w/ a different course than is in the scenario_dict? if so, why? If not,
# then get rid of the override arg
def course_id(course_num):
    return world.scenario_dict['COURSE'].id.replace(course=course_num)


def course_location(course_num):
    return world.scenario_dict['COURSE'].location.replace(course=course_num)


def section_location(course_num):
    return world.scenario_dict['SECTION'].location.replace(course=course_num)


def visit_scenario_item(item_key):
    """
    Go to the courseware page containing the item stored in `world.scenario_dict`
    under the key `item_key`
    """

    url = django_url(reverse(
        'jump_to',
        kwargs={
            'course_id': unicode(world.scenario_dict['COURSE'].id),
            'location': unicode(world.scenario_dict[item_key].location),
        }
    ))

    world.browser.visit(url)


def get_courses():
    '''
    Returns dict of lists of courses available, keyed by course.org (ie university).
    Courses are sorted by course.number.
    '''
    courses = [c for c in modulestore().get_courses()
               if isinstance(c, CourseDescriptor)]  # skip error descriptors
    courses = sorted(courses, key=lambda course: course.location.course)
    return courses


def get_courseware_with_tabs(course_id):
    """
    Given a course_id (string), return a courseware array of dictionaries for the
    top three levels of navigation. Same as get_courseware() except include
    the tabs on the right hand main navigation page.

    This hides the appropriate courseware as defined by the hide_from_toc field:
    chapter.hide_from_toc

    Example:

    [{
        'chapter_name': 'Overview',
        'sections': [{
            'clickable_tab_count': 0,
            'section_name': 'Welcome',
            'tab_classes': []
        }, {
            'clickable_tab_count': 1,
            'section_name': 'System Usage Sequence',
            'tab_classes': ['VerticalBlock']
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Lab0: Using the tools',
            'tab_classes': ['HtmlDescriptor', 'HtmlDescriptor', 'CapaDescriptor']
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Circuit Sandbox',
            'tab_classes': []
        }]
    }, {
        'chapter_name': 'Week 1',
        'sections': [{
            'clickable_tab_count': 4,
            'section_name': 'Administrivia and Circuit Elements',
            'tab_classes': ['VerticalBlock', 'VerticalBlock', 'VerticalBlock', 'VerticalBlock']
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Basic Circuit Analysis',
            'tab_classes': ['CapaDescriptor', 'CapaDescriptor', 'CapaDescriptor']
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Resistor Divider',
            'tab_classes': []
        }, {
            'clickable_tab_count': 0,
            'section_name': 'Week 1 Tutorials',
            'tab_classes': []
        }]
    }, {
        'chapter_name': 'Midterm Exam',
        'sections': [{
            'clickable_tab_count': 2,
            'section_name': 'Midterm Exam',
            'tab_classes': ['VerticalBlock', 'VerticalBlock']
        }]
    }]
    """

    course = get_course_by_id(course_id)
    chapters = [chapter for chapter in course.get_children() if not chapter.hide_from_toc]
    courseware = [{
        'chapter_name': c.display_name_with_default_escaped,
        'sections': [{
            'section_name': s.display_name_with_default_escaped,
            'clickable_tab_count': len(s.get_children()) if (type(s) == seq_module.SequenceDescriptor) else 0,
            'tabs': [{
                'children_count': len(t.get_children()) if (type(t) == vertical_block.VerticalBlock) else 0,
                'class': t.__class__.__name__} for t in s.get_children()
            ]
        } for s in c.get_children() if not s.hide_from_toc]
    } for c in chapters]

    return courseware
