# -*- coding: utf-8 -*-
#
# Copyright (c) 2014-2015 Harvard, edX & OpenCraft
#
# This software's license gives you freedom; you can copy, convey,
# propagate, redistribute and/or modify this program under the terms of
# the GNU Affero General Public License (AGPL) as published by the Free
# Software Foundation (FSF), either version 3 of the License, or (at your
# option) any later version of the AGPL published by the FSF.
#
# This program is distributed in the hope that it will be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero
# General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program in a file in the toplevel directory called
# "AGPLv3".  If not, see <http://www.gnu.org/licenses/>.
#

# Imports ###########################################################

import logging
import uuid

from xblock.core import XBlock
from xblock.fields import Scope, String, Float
from xblock.fragment import Fragment
from xblockutils.studio_editable import StudioEditableXBlockMixin
from xblockutils.resources import ResourceLoader

from .mixins import QuestionMixin, XBlockWithTranslationServiceMixin
from .sub_api import sub_api, SubmittingXBlockMixin


# Globals ###########################################################

log = logging.getLogger(__name__)
loader = ResourceLoader(__name__)


# Make '_' a no-op so we can scrape strings
def _(text):
    return text

# Classes ###########################################################


@XBlock.needs("i18n")
class SliderBlock(
    SubmittingXBlockMixin, QuestionMixin, StudioEditableXBlockMixin, XBlockWithTranslationServiceMixin, XBlock,
):
    """
    An XBlock used by students to indicate a numeric value on a sliding scale.
    The student's answer is always considered "correct".
    """
    CATEGORY = 'pb-slider'
    STUDIO_LABEL = _(u"Ranged Value Slider")
    answerable = True

    min_label = String(
        display_name=_("Low"),
        help=_("Label for low end of the range"),
        scope=Scope.content,
        default=_("0%"),
    )
    max_label = String(
        display_name=_("High"),
        help=_("Label for high end of the range"),
        scope=Scope.content,
        default=_("100%"),
    )

    question = String(
        display_name=_("Question"),
        help=_("Question to ask the student (optional)"),
        scope=Scope.content,
        default="",
        multiline_editor=True,
    )

    student_value = Float(
        # The value selected by the student
        default=None,
        scope=Scope.user_state,
    )

    editable_fields = ('min_label', 'max_label', 'display_name', 'question', 'show_title')

    def mentoring_view(self, context):
        """ Main view of this block """
        context = context.copy() if context else {}
        context['question'] = self.question
        context['slider_id'] = 'pb-slider-{}'.format(uuid.uuid4().hex[:20])
        context['initial_value'] = int(self.student_value*100) if self.student_value is not None else 50
        context['min_label'] = self.min_label
        context['max_label'] = self.max_label
        context['title'] = self.display_name_with_default
        context['hide_header'] = context.get('hide_header', False) or not self.show_title
        context['instructions_string'] = self._("Select a value from {min_label} to {max_label}").format(
            min_label=self.min_label, max_label=self.max_label
        )
        html = loader.render_template('templates/html/slider.html', context)

        fragment = Fragment(html)
        fragment.add_javascript_url(self.runtime.local_resource_url(self, 'public/js/slider.js'))
        fragment.initialize_js('SliderBlock')
        return fragment

    student_view = mentoring_view
    preview_view = mentoring_view

    def author_view(self, context):
        """
        Add some HTML to the author view that allows authors to see the ID of the block, so they
        can refer to it in other blocks such as Plot blocks.
        """
        context['hide_header'] = True  # Header is already shown in the Studio wrapper
        fragment = self.student_view(context)
        fragment.add_content(loader.render_template('templates/html/slider_edit_footer.html', {
            "url_name": self.url_name
        }))
        return fragment

    def get_last_result(self):
        """ Return the current/last result in the required format """
        if self.student_value is None:
            return {}
        return {
            'submission': self.student_value,
            'status': 'correct',
            'tips': [],
            'weight': self.weight,
            'score': 1,
        }

    def get_results(self, _previous_result_unused=None):
        """ Alias for get_last_result() """
        return self.get_last_result()

    def submit(self, value):
        log.debug(u'Received Slider submission: "%s"', value)
        if value < 0 or value > 1:
            return {}  # Invalid
        self.student_value = value
        if sub_api:
            # Also send to the submissions API:
            sub_api.create_submission(self.student_item_key, {'value': value})
        result = self.get_last_result()
        log.debug(u'Slider submission result: %s', result)
        return result

    def validate_field_data(self, validation, data):
        """
        Validate this block's field data.
        """
        super(SliderBlock, self).validate_field_data(validation, data)
