"""
Validate Course / Predict Inputs for advanced fields
"""
import uuid
import json
import yaml
import datetime

from frontend_env import *


class VEDACat(object):

    def __init__(self, **kwargs):

        self.model_yaml = kwargs.get(
            'model_yaml',
            os.path.join(
                os.path.dirname(os.path.abspath(__file__)),
                'veda_models.yaml'
            )
        )
        self.veda_model = self._READ_HEURISTICS()
        self.inst_code = kwargs.get('inst_code', None)
        self.course_code = kwargs.get('course_code', None)
        self.inst_list = {}
        self.return_fields = {}

    def _READ_HEURISTICS(self):
        """
        Load in the heuristics from the sidecar yaml
        """
        with open(self.model_yaml, 'r') as stream:
            try:
                set_dict = yaml.load(stream)
                return set_dict
            except yaml.YAMLError as exc:
                return None

    def institution_name(self):
        """
        Validate institution input code
        """
        try:
            inst_query = Institution.objects.filter(
                institution_code=self.inst_code
            )
            return inst_query[0].institution_name
        except:
            return 'Error'

    def institution_list(self):
        inst_query = Institution.objects.filter()
        for i in inst_query:
            self.inst_list[i.institution_code] = i.institution_name

    def validate_inst(inst_code):
        """
        check 3 digit institution code
        """
        try:
            i = Institution.objects.filter(
                institution_code=inst_code,
            )
            data = i[0].institution_name
        except:
            """
            If Institution does not Exist // since there are some blank fields
            """
            data = '0'
        return data

    def institution_data(self):
        inst_data = {}
        field_data = {}
        booleans = {}
        dropdowns = {}
        must_haves = {}
        if self.inst_code == 'NEWINST':
            # Just to get the models
            course_query = Course.objects.filter(
                institution='XXX',
                edx_classid='XXXXX'
            )

        else:
            """
            Get courses that match inst_code, active,(TODO?:) within last 6 mos.
            """
            course_query = Course.objects.filter(
                institution=self.inst_code,
                course_hold=True,
            )

        if len(course_query) > 0:
            mod_q = course_query[0]._meta.get_fields()
        else:
            """
            TODO: Build out error here
            """
            return None
        """
        Generate return fields
        """
        for m in mod_q:

            if m.name not in self.veda_model['models_nottoget']:

                field_data[m.name] = m.verbose_name

                if m.name in self.veda_model['bools']:
                    booleans[m.name] = m.verbose_name
                if m.name in self.veda_model['dropdowns']:
                    dropdowns[m.name] = m.verbose_name

                if m.name in self.veda_model['must_haves']:
                    must_haves[m.name] = m.verbose_name

                if m.name not in self.veda_model['must_haves']:
                    if self.inst_code != 'NEWINST':
                        correlation = []
                        for c in course_query:
                            correlation.append(getattr(c, m.name))

                        majority = self.simple_majority(
                            attribute_list=correlation
                        )

                        if majority['majority'] is not False:
                            inst_data[m.name] = majority['field']

        self.return_fields['field_data'] = field_data
        self.return_fields['inst_data'] = inst_data
        self.return_fields['booleans'] = booleans
        self.return_fields['dropdowns'] = dropdowns
        self.return_fields['must_haves'] = must_haves
        self.return_fields['organizational'] = self.veda_model['organizational']

    def validate_code(self, course_code):
        """
        check 5 digit course code
        """
        code_query = Course.objects.filter(
            institution=self.inst_code,
            edx_classid=course_code[0:5]
        )
        if len(code_query) > 0:
            return False

        return True

    def rand_gen(self):
        return uuid.uuid1().hex[0:5]

    def generate_code(self, gen_seed):
        code = ''

        for i in gen_seed:
            if i.isupper() and len(code) < 5:
                code += i.upper()

            if i.isdigit() and len(code) < 5:
                code += i
        if len(code) < 5:
            while len(code) < 5:
                code += 'X'

        truth = self.validate_code(
            course_code=code
        )
        if truth is True:
            return code[0:5]

        else:
            """
            Generate Random ID until it's unique
            """
            while truth is False:
                code = self.rand_gen().upper()
                truth = self.validate_code(
                    course_code=code
                )
            return code[0:5]

    def course_add(self, return_data):
        data = json.loads(return_data)
        c1 = Course(institution=data['institution'])

        if 'institution_name' in data:
            i1 = Institution(
                institution_name=data['institution_name'],
                institution_code=data['institution']
            )
            i1.save()

        '''Checkbox/false doesn't show up'''
        for x in self.veda_model['bools']:
            if x not in [a for a, b in data.iteritems()]:
                setattr(c1, x, False)

        """
        decode undecodable characters
        """
        decode_data = data
        for a, b in decode_data.iteritems():
            if isinstance(b, unicode):
                try:
                    b.encode('ascii')
                except:
                    data[a] = b.encode('ascii', errors='replace')

        """
        Translate fields into django models
        """
        for a, b in data.iteritems():
            if b is not None:

                if a != 'institution' and a != 'class_name' and len(str(b)) > 0:
                    setattr(c1, a, b)

                '''
                AutoGenerate Sometimes
                '''
                # SET RULES
                if a == 'edx_classid' and len(b) == 0:
                    self.inst_code = data['institution']

                    edx_classid = self.generate_code(
                        gen_seed=data['course_name']
                    )
                    setattr(c1, 'edx_classid', edx_classid)

                elif a == 'edx_classid' and len(b) != 0:

                    c2 = Course.objects.filter(
                        institution=data['institution'],
                        edx_classid=b
                    )

                    if len(c2) > 0:
                        self.inst_code = data['institution']

                        edx_classid = self.generate_code(
                            gen_seed=data['course_name']
                        )
                        setattr(c1, 'edx_classid', edx_classid)

                    else:
                        edx_classid = b
                        setattr(c1, 'edx_classid', edx_classid)

                if a == 'yt_channel' and len(b) == 0:
                    setattr(c1, 'yt_proc', False)
                else:
                    setattr(c1, 'yt_proc', True)

                if a == 'tp_username' and len(b) == 0:
                    setattr(c1, 'tp_proc', False)
                if a == 'tp_pass' and len(b) == 0:
                    setattr(c1, 'tp_proc', False)

        """Always Set"""
        setattr(c1, 'course_hold', True)  # Remember, this is reversed

        # Semester
        c1.semesterid = str(datetime.datetime.now().year)

        # Just in case (probably overengineered)
        c2 = Course.objects.filter(
            institution=data['institution'],
            edx_classid=edx_classid
        )
        if len(c2) > 0:
            return {}

        c1.previous_statechange = datetime.datetime.utcnow().replace(tzinfo=utc)
        c1.save()

        return_dict = {}
        return_dict['course_code'] = c1.institution + c1.edx_classid + c1.semesterid
        return_dict['studio_hex'] = c1.studio_hex

        return return_dict

    def simple_majority(self, attribute_list):
        """
        Simple Majority Finder
        Field attribute for 'most' of them (>50.0%) per attrib
        """
        comparitor = {'None': 0}
        for a in attribute_list:
            in_it = False
            for b, c in comparitor.iteritems():
                if a is None:
                    comparitor['None'] += 1
                if a == b:
                    comparitor[a] += 1
                    in_it = True
                else:
                    pass
            if in_it is False:
                comparitor[a] = 1

        data = {}

        for d, e in comparitor.iteritems():
            if e > len(attribute_list) * 0.5:
                data['majority'] = True
                data['field'] = d

        if len(data) == 0:
            data['majority'] = False

        return data