# -*- coding: utf-8 -*-
from collections import defaultdict
from datetime import date, datetime
from django.conf import settings

from events.common_app.utils import lazy_re_compile
from events.common_storages.models import ProxyStorageModel
from events.surveyme.dataclasses import ParamQuiz, SurveyQuiz


SIMPLE_ANSWER_TYPE_SLUGS = set([
    'answer_short_text',
    'answer_long_text',
    'answer_number',
    'answer_non_profile_email',
    'answer_boolean',
    'answer_url',
    'answer_phone',
    'answer_name',
    'answer_surname',
    'answer_payment',
])


def get_answer_type_data(answer_type):
    return {
        'id': answer_type.pk,
        'slug': answer_type.slug,
    }


def get_options_data(survey_question):
    options = {}
    if survey_question.param_is_required:
        options['required'] = True
    if survey_question.answer_type.slug == 'answer_choices':
        options['data_source'] = survey_question.param_data_source
        options['multiple'] = survey_question.param_is_allow_multiple_choice
        options['ordering'] = survey_question.param_modify_choices
    if survey_question.answer_type.slug == 'answer_date':
        options['date_range'] = survey_question.param_date_field_type == 'daterange'
    if survey_question.answer_type.slug == 'answer_payment':
        param_payment = survey_question.param_payment or {}
        options['account_id'] = param_payment.get('account_id')
    return options


def get_question_data(survey_question):
    question_data = {
        'id': survey_question.pk,
        'slug': survey_question.param_slug,
        'answer_type': get_answer_type_data(survey_question.answer_type),
    }
    options = get_options_data(survey_question)
    if options:
        question_data['options'] = options
    return question_data


def isoformat(dt):
    if isinstance(dt, datetime):
        return dt.strftime('%Y-%m-%dT%H:%M:%SZ')
    if isinstance(dt, date):
        return dt.strftime('%Y-%m-%d')


def get_answer_date_data(survey_question, cleaned_data, group_slug=None):
    value = cleaned_data.get(group_slug or survey_question.param_slug)
    if value:
        is_date_range = survey_question.param_date_field_type == 'daterange'
        if is_date_range:
            return {
                'begin': isoformat(value.get('date_start')),
                'end': isoformat(value.get('date_end')),
            }
        else:
            return isoformat(value.get('date_start'))


def get_answer_files_data(survey_question, cleaned_data, group_slug=None):
    value = cleaned_data.get(group_slug or survey_question.param_slug)
    if value:
        return [
            {
                'path': file_item.path,
                'size': file_item.file_size,
                'name': file_item.original_name,
                'namespace': file_item.namespace or settings.MDS_OLD_NAMESPACE,
            }
            for file_item in ProxyStorageModel.objects.filter(path__in=value)
        ]


def get_survey_question_choice_data(survey_question, value):
    choices = {
        str(choice.pk): {
            'key': str(choice.pk),
            'slug': choice.slug,
            'text': choice.label,
        }
        for choice in survey_question.surveyquestionchoice_set.all()
    }
    data = [
        choices.get(data_item.identity)
        for data_item in value
    ]
    return data


def get_survey_question_matrix_choice_data(survey_question, value):
    rows, cols = [], []
    for title in survey_question.surveyquestionmatrixtitle_set.all():
        if title.type == 'row':
            rows.append((title.pk, title.label))
        elif title.type == 'column':
            cols.append((title.pk, title.label))
    matrix_titles = {
        '{}_{}'.format(row_id, col_id): {
            'row': {
                'key': str(row_id),
                'text': row_text,
            },
            'col': {
                'key': str(col_id),
                'text': col_text,
            },
        }
        for row_id, row_text in rows
        for col_id, col_text in cols
    }
    return [
        matrix_titles.get(data_item.identity)
        for data_item in value
    ]


def get_yt_table_data(survey_question, value):
    from events.data_sources.models import TableRow
    pks = (
        data_item.identity
        for data_item in value
    )
    return [
        {
            'key': str(key),
            'slug': slug,
            'text': text,
        }
        for key, slug, text in TableRow.objects.filter(pk__in=pks).values_list('id', 'source_id', 'text')
    ]


def get_survey_question_data_source(survey_question, value):
    return [
        {
            'key': data_item.identity,
            'text': data_item.get_text(),
        }
        for data_item in value
    ]


def get_answer_choices_data(survey_question, cleaned_data, group_slug=None):
    value = cleaned_data.get(group_slug or survey_question.param_slug)
    if value:
        if survey_question.param_data_source == 'survey_question_choice':
            return get_survey_question_choice_data(survey_question, value)
        if survey_question.param_data_source == 'survey_question_matrix_choice':
            return get_survey_question_matrix_choice_data(survey_question, value)
        if survey_question.param_data_source == 'yt_table_source':
            return get_yt_table_data(survey_question, value)
        return get_survey_question_data_source(survey_question, value)


group_question_re = lazy_re_compile(r'^(?P<slug>.+?)__(?P<counter>\d+)$')


def get_answer_group_data(survey_question, cleaned_data):
    survey = survey_question.survey

    # определяем какие поля для групп были переданы в запросе
    slugs = defaultdict(set)
    for question_slug in cleaned_data.keys():
        m = group_question_re.match(question_slug)
        if m:
            slugs[m.group('slug')].add(int(m.group('counter')))
    if not slugs:
        return None

    # составляем связь между вопросами и индексами внутри группы
    child_questions = defaultdict(list)
    for item in survey.surveyquestion_set.all():
        if item.group_id == survey_question.pk:
            for item_index in slugs.get(item.param_slug, []):
                child_questions[item_index].append(item)
    if not child_questions:
        return None

    data = []
    for i in range(max(child_questions.keys()) + 1):
        fieldset = [
            get_answer_question_data(
                item,
                cleaned_data,
                group_slug='{}__{}'.format(item.param_slug, i),
            )
            for item in child_questions.get(i, [])
        ]
        if fieldset:
            data.append(fieldset)
    return data


def get_value_data(survey_question, cleaned_data, group_slug=None):
    answer_type_slug = survey_question.answer_type.slug
    if answer_type_slug in SIMPLE_ANSWER_TYPE_SLUGS:
        return cleaned_data.get(group_slug or survey_question.param_slug)
    if answer_type_slug == 'answer_date':
        return get_answer_date_data(survey_question, cleaned_data, group_slug)
    if answer_type_slug == 'answer_files':
        return get_answer_files_data(survey_question, cleaned_data, group_slug)
    if answer_type_slug == 'answer_choices':
        return get_answer_choices_data(survey_question, cleaned_data, group_slug)
    if answer_type_slug == 'answer_group':
        return get_answer_group_data(survey_question, cleaned_data)


def make_decimal(survey_question, value):
    if not survey_question.validator_type_id or survey_question.validator_type.slug != 'decimal':
        return value
    return value.replace(',', '.')


def get_scores_data(survey_question, value):
    param_quiz = ParamQuiz(survey_question.param_quiz)
    if param_quiz.enabled:
        # формируем список с пользовательскими ответами
        if isinstance(value, list):
            user_answers = {it.get('text') for it in value}
        else:
            user_answers = {make_decimal(survey_question, value)}

        # формируем словарь с правильными ответами
        correct_answers = {
            answer.value: answer.scores
            for answer in param_quiz.answers
            if answer.correct
        }

        # больше не полагаемся на param_quiz.required,
        # проверяем что тип вопроса Список и множественный выбор (чекбоксы)
        if survey_question.param_is_allow_multiple_choice:
            if user_answers != set(correct_answers.keys()):
                return 0.0

        # проверяем правильные ответы и начисляем очки
        scores = 0.0
        for user_answer in user_answers:
            scores += correct_answers.get(user_answer, 0)
        return scores


def get_answer_question_data(survey_question, cleaned_data, group_slug=None):
    value = get_value_data(survey_question, cleaned_data, group_slug)
    if value is not None:
        answer_question_data = {
            'question': get_question_data(survey_question),
            'value': value
        }
        scores = get_scores_data(survey_question, value)
        if scores is not None:
            answer_question_data['scores'] = scores
        return answer_question_data


def get_quiz_data(survey, scores):
    if survey.quiz_question_count > 0:
        extra = survey.extra or {}
        quiz = SurveyQuiz(extra.get('quiz'))
        quiz_item = quiz.get_item(survey.total_scores, scores)
        return {
            'total_scores': survey.total_scores,
            'question_count': survey.quiz_question_count,
            'scores': scores,
            'title': quiz_item.title,
            'description': quiz_item.description,
            'image_path': quiz_item.get_image_path(),
        }


def uid_as_string(user):
    if user and user.uid:
        return str(user.uid)


def get_answer_data(survey, answer, cleaned_data):
    data = []
    scores = 0.0
    for survey_question in survey.surveyquestion_set.all():
        if survey_question.group_id is None:
            value = get_answer_question_data(survey_question, cleaned_data)
            if value is not None:
                if survey.total_scores is not None:
                    scores += value.get('scores', 0)
                data.append(value)

    answer_data = {
        'id': int(answer.pk),
        'uid': uid_as_string(answer.user),
        'created': isoformat(answer.date_created),
        'survey': {
            'id': str(survey.pk),
            'slug': survey.slug,
        },
        'data': data,
    }

    cloud_uid = answer.user.cloud_uid
    if cloud_uid:
        answer_data['cloud_uid'] = cloud_uid

    if survey.quiz_question_count > 0:
        answer_data['quiz'] = get_quiz_data(survey, scores)
    return answer_data
