# -*- coding: utf-8 -*-

from abc import ABC, abstractmethod

from . import grammar_defines
from . import string_utils
from . import exceptions
from . import parse_verbs
from . import parse_conjugations

class Inflector(ABC):
    def __init__(self):
        self._verb_parser = parse_verbs.VerbsParser(self.lang)
        self._conj_parser = parse_conjugations.ConjugationsParser(self.lang)

    def conjugate(self, infinitive):
        co = self._get_conj_obs(infinitive)
        moods = {}
        for mood in co.template.moods:
            moods[mood] = self._conjugate_mood(co, mood)
        return {'verb': {'infinitive': co.verb.infinitive, 
                         'template': co.verb.template,
                         'translation_en': co.verb.translation_en,
                         'stem': co.verb_stem}, 
                'moods': moods}

    def conjugate_mood(self, infinitive, mood_name):
        co = self._get_conj_obs(infinitive)
        return self._conjugate_mood(co, mood_name)

    def conjugate_mood_tense(self, infinitive, mood_name, tense_name):
        co = self._get_conj_obs(infinitive)
        return self._conjugate_mood_tense(co, mood_name, tense_name)

    def find_verb_by_infinitive(self, infinitive):
        return self._verb_parser.find_verb_by_infinitive(infinitive)

    def find_template(self, name):
        return self._conj_parser.find_template(name)

    def get_verbs_that_start_with(self, query, max_results):
        query = query.lower()
        matches = self._verb_parser.get_verbs_that_start_with(query, max_results)
        return matches

    def _get_verb_stem(self, infinitive, template_name):
        template_beg, template_ending = template_name.split(u':')
        if not infinitive.endswith(template_ending):
            raise exceptions.ConjugatorError(
                "Template {} ending doesn't "
                "match infinitive {}"
                .format(template_name, infinitive))
        return infinitive[:len(infinitive) - len(template_ending)]

    def _is_impersonal_verb(self, infinitive):
        return False

    def _verb_can_be_reflexive(self, infinitive):
        return not self._is_impersonal_verb(infinitive)

    def _split_reflexive(self, infinitive):
        return (False, infinitive)

    class ConjugationObjects:
        def __init__(self, infinitive, verb, template, verb_stem, is_reflexive):
            self.infinitive = infinitive
            self.verb = verb
            self.template = template
            self.verb_stem = verb_stem
            self.is_reflexive = is_reflexive

    def _get_conj_obs(self, infinitive):
        infinitive = infinitive.lower()
        is_reflexive, infinitive = self._split_reflexive(infinitive)
        if is_reflexive and not self._verb_can_be_reflexive(infinitive):
            raise exceptions.VerbNotFoundError("Verb cannot be reflexive")
        verb = self.find_verb_by_infinitive(infinitive)
        template = self.find_template(verb.template)
        verb_stem = self._get_verb_stem(verb.infinitive, template.name)
        return Inflector.ConjugationObjects(
            infinitive, verb, template, verb_stem, is_reflexive)     

    def _conjugate_mood(self, co, mood_name):
        if mood_name not in co.template.moods:
            raise exceptions.InvalidMoodError
        ret = {}
        ret.update(self._get_simple_conjugations_for_mood(co, mood_name))
        ret.update(self._get_compound_conjugations_for_mood(co, mood_name))
        return ret

    def _get_simple_conjugations_for_mood(self, co, mood_name):
        ret = {}
        mood = co.template.moods[mood_name]
        for tense_name in mood.tenses:
            ret[tense_name] = self._conjugate_mood_tense(co, mood_name, tense_name)
        return ret

    def _get_compound_conjugations_for_mood(self, co, mood_name):
        ret = {}
        comp_conj_map = self._get_compound_conjugations_hv_map()
        if mood_name in comp_conj_map:
            for tense_name in comp_conj_map[mood_name]:
                ret[tense_name] = self._conjugate_mood_tense(co, mood_name, tense_name)
        return ret

    def _conjugate_mood_tense(self, co, mood_name, tense_name):
        comp_conj_map = self._get_compound_conjugations_hv_map()
        if mood_name in comp_conj_map and tense_name in comp_conj_map[mood_name]:
            hv_tense_name = comp_conj_map[mood_name][tense_name]
            return self._conjugate_compound(co, mood_name, hv_tense_name)
        else:
            mood = co.template.moods[mood_name]
            if tense_name not in mood.tenses:
                raise exceptions.InvalidTenseError
            tense_template = mood.tenses[tense_name]
            return self._conjugate_simple_mood_tense(
                co.verb_stem, mood_name, tense_template,
                co.is_reflexive)

    def _get_compound_conjugations_hv_map(self):
        """"Returns a map of the tense of the helping verb for each compound mood and tense"""
        return {}

    def _conjugate_compound(self, co, mood_name, hv_tense_name):
        """Conjugate a compound tense
        Args:
            co: ConjugationObjects for the verb being conjugated
            mood_name: mood verb is being conjugated in
            hv_tense_name: tense_name for conjugating helping verb
        """
        return {}

    def _get_default_participle_inflection_for_person(self, person):
        if person[1] == 's':
            return 'ms'
        else:
            return 'mp'

    def _get_default_pronoun(self, person, gender='m', is_reflexive=False):
        return ''

    def _conjugate_simple_mood_tense(self, verb_stem, mood_name, 
                                     tense_template, is_reflexive=False):
        ret = []
        for person_ending in tense_template.person_endings:
            pronoun = self._get_default_pronoun(
                person_ending.get_person(), is_reflexive=is_reflexive)
            ending = person_ending.get_ending()

            conjugation = ''
            conjugated_verb = verb_stem + ending
            if pronoun[-1] == "e" and string_utils.starts_with_vowel(conjugated_verb):
                conjugation += pronoun[:-1] + "'"
            else:
                conjugation += pronoun + " "
            conjugation += conjugated_verb

            if mood_name == 'subjonctif':
                conjugation = prepend_with_que(conjugation)
            ret.append(conjugation)
        return ret
