from typing import Dict, List, Optional
from .question_creators.question_creator import QuestionCreator

from .question_creators.general.antonym_question_creator import AntonymQuestionCreator
from .question_creators.general.choice_english_definitions_question_creator import (
    ChoiceEnglishDefinitionsQuestionCreator,
)
from .question_creators.general.choice_spanish_definitions_question_creator import (
    ChoiceSpanishDefinitionsQuestionCreator,
)
from .question_creators.general.conjugation_question_creator import (
    ConjugationQuestionCreator,
)
from .question_creators.general.dual_video_spanish_definitions_question_creator import (
    DualVideoSpanishDefinitionsQuestionCreator,
)
from .question_creators.general.fullword_scrabble_question_creator import (
    FullWordScrabbleQuestionCreator,
)
from .question_creators.general.fullword_typing_question_creator import (
    FullWordTypingQuestionCreator,
)
from .question_creators.general.gap_question_creator import GapQuestionCreator
from .question_creators.general.intruder_question_creator import IntruderQuestionCreator
from .question_creators.general.means_like_question_creator import (
    MeansLikeQuestionCreator,
)
from .question_creators.general.minimal_pairs_question_creator import (
    MinimalPairsQuestionCreator,
)
from .question_creators.general.multisynonym_question_creator import (
    MultiSynonymQuestionCreator,
)
from .question_creators.general.partword_typing_question_creator import (
    PartWordTypingQuestionCreator,
)
from .question_creators.general.relnoun_question_creator import RelNounQuestionCreator
from .question_creators.general.sentence_scrabble_question_creator import (
    SentenceScrabbleQuestionCreator,
)
from .question_creators.general.subword_question_creator import SubwordQuestionCreator
from .question_creators.general.synonym_question_creator import SynonymQuestionCreator
from .question_creators.general.tense_verb_choice_question_creator import (
    TenseVerbChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.future_continuous.future_continuous_choice_question_creator import (
    FutureContinuousChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.future_continuous.future_continuous_negative_choice_question_creator import (
    FutureContinuousNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.future_perfect.future_perfect_choice_question_creator import (
    FuturePerfectChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.future_perfect.future_perfect_negative_choice_question_creator import (
    FuturePerfectNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.future_perfect_continuous.future_perfect_continuous_choice_question_creator import (
    FuturePerfectContinuousChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.future_perfect_continuous.future_perfect_continuous_negative_choice_question_creator import (
    FuturePerfectContinuousNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.going_to_future.future_dual_video_question_creator import (
    FutureDualVideoQuestionCreator,
)
from .question_creators.patterns.verbs.going_to_future.going_to_future_choice_question_creator import (
    GoingToFutureChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.going_to_future.going_to_future_negative_choice_question_creator import (
    GoingToFutureNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.irregular_past_tense.irregular_past_tense_choice_question_creator import (
    IrregularPastTenseChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.passive_voice.passive_voice_choice_question_creator import (
    PassiveVoiceChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.past_continuous.past_continuous_choice_question_creator import (
    PastContinuousChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.past_continuous.past_continuous_negation_choice_question_creator import (
    PastContinuousNegationChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.past_perfect.past_perfect_choice_question_creator import (
    PastPerfectChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.past_perfect.past_perfect_negation_choice_question_creator import (
    PastPerfectNegationChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.past_perfect_continuous.past_perfect_continuous_choice_question_creator import (
    PastPerfectContinuousChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.past_perfect_continuous.past_perfect_continuous_negative_choice_question_creator import (
    PastPerfectContinuousNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_choice_question_creator import (
    PresentContinuousChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_full_typing_question_creator import (
    PresentContinuousFullWordTypingQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_interrogation_partword_typing_question_creator import (
    PresentContinuousInterrogationPartWordTypingQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_negative_choice_question_creator import (
    PresentContinuousNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_negative_full_typing_question_creator import (
    PresentContinuousNegativeFullWordTypingQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_negative_partword_typing_question_creator import (
    PresentContinuousNegativePartWordTypingQuestionCreator,
)
from .question_creators.patterns.verbs.present_continuous.present_continuous_partword_typing_question_creator import (
    PresentContinuousPartWordTypingQuestionCreator,
)
from .question_creators.patterns.verbs.present_perfect.present_perfect_choice_question_creator import (
    PresentPerfectChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.present_perfect.present_perfect_negation_choice_question_creator import (
    PresentPerfectNegationChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.present_perfect_continuous.present_perfect_continuous_choice_question_creator import (
    PresentPerfectContinuousChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.present_perfect_continuous.present_perfect_continuous_negative_choice_question_creator import (
    PresentPerfectContinuousNegativeChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.simple_future.simple_future_choice_question_creator import (
    SimpleFutureChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.simple_future.simple_future_choice_two_question_creator import (
    SimpleFutureChoiceTwoQuestionCreator,
)
from .question_creators.patterns.verbs.simple_future.simple_future_negation_choice_question_creator import (
    SimpleFutureNegationChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.simple_past.simple_past_negation_choice_question_creator import (
    SimplePastNegationChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.simple_present.simple_present_negation_choice_question_creator import (
    SimplePresentNegationChoiceQuestionCreator,
)
from .question_creators.patterns.verbs.simple_present.simple_tense_choice_question_creator import (
    SimpleTenseChoiceQuestionCreator,
)

QUESTION_PACK_TEST_CODE = "GMPT"
QUESTION_PACK_ALL_CODE = "GMPALL"

question_type_to_creator = {
    GapQuestionCreator.code: GapQuestionCreator,
    MinimalPairsQuestionCreator.code: MinimalPairsQuestionCreator,
    SubwordQuestionCreator.code: SubwordQuestionCreator,
    PartWordTypingQuestionCreator.code: PartWordTypingQuestionCreator,
    DualVideoSpanishDefinitionsQuestionCreator.code: DualVideoSpanishDefinitionsQuestionCreator,
    ChoiceSpanishDefinitionsQuestionCreator.code: ChoiceSpanishDefinitionsQuestionCreator,
    SynonymQuestionCreator.code: SynonymQuestionCreator,
    AntonymQuestionCreator.code: AntonymQuestionCreator,
    MeansLikeQuestionCreator.code: MeansLikeQuestionCreator,
    RelNounQuestionCreator.code: RelNounQuestionCreator,
    MultiSynonymQuestionCreator.code: MultiSynonymQuestionCreator,
    IntruderQuestionCreator.code: IntruderQuestionCreator,
    ChoiceEnglishDefinitionsQuestionCreator.code: ChoiceEnglishDefinitionsQuestionCreator,
    FullWordScrabbleQuestionCreator.code: FullWordScrabbleQuestionCreator,
    SentenceScrabbleQuestionCreator.code: SentenceScrabbleQuestionCreator,
    FullWordTypingQuestionCreator.code: FullWordTypingQuestionCreator,
    ConjugationQuestionCreator.code: ConjugationQuestionCreator,
    TenseVerbChoiceQuestionCreator.code: TenseVerbChoiceQuestionCreator,
    SimpleTenseChoiceQuestionCreator.code: SimpleTenseChoiceQuestionCreator,
    GoingToFutureChoiceQuestionCreator.CODE: GoingToFutureChoiceQuestionCreator,
    SimplePresentNegationChoiceQuestionCreator.CODE: SimplePresentNegationChoiceQuestionCreator,
    SimplePastNegationChoiceQuestionCreator.CODE: SimplePastNegationChoiceQuestionCreator,
    IrregularPastTenseChoiceQuestionCreator.CODE: IrregularPastTenseChoiceQuestionCreator,
    PastContinuousChoiceQuestionCreator.CODE: PastContinuousChoiceQuestionCreator,
    PastContinuousNegationChoiceQuestionCreator.CODE: PastContinuousNegationChoiceQuestionCreator,
    PresentContinuousNegativeChoiceQuestionCreator.CODE: PresentContinuousNegativeChoiceQuestionCreator,
    PresentPerfectChoiceQuestionCreator.CODE: PresentPerfectChoiceQuestionCreator,
    PresentPerfectNegationChoiceQuestionCreator.CODE: PresentPerfectNegationChoiceQuestionCreator,
    PresentPerfectContinuousNegativeChoiceQuestionCreator.code: PresentPerfectContinuousNegativeChoiceQuestionCreator,
    PresentPerfectContinuousChoiceQuestionCreator.code: PresentPerfectContinuousChoiceQuestionCreator,
    PassiveVoiceChoiceQuestionCreator.code: PassiveVoiceChoiceQuestionCreator,
    SimpleFutureNegationChoiceQuestionCreator.CODE: SimpleFutureNegationChoiceQuestionCreator,
    PastPerfectChoiceQuestionCreator.CODE: PastPerfectChoiceQuestionCreator,
    PastPerfectNegationChoiceQuestionCreator.CODE: PastPerfectNegationChoiceQuestionCreator,
    FuturePerfectChoiceQuestionCreator.CODE: FuturePerfectChoiceQuestionCreator,
    FuturePerfectNegativeChoiceQuestionCreator.CODE: FuturePerfectNegativeChoiceQuestionCreator,
    PastPerfectContinuousChoiceQuestionCreator.CODE: PastPerfectContinuousChoiceQuestionCreator,
    PastPerfectContinuousNegativeChoiceQuestionCreator.CODE: PastPerfectContinuousNegativeChoiceQuestionCreator,
    SimpleFutureChoiceQuestionCreator.code: SimpleFutureChoiceQuestionCreator,
    SimpleFutureChoiceTwoQuestionCreator.code: SimpleFutureChoiceTwoQuestionCreator,
    FutureContinuousChoiceQuestionCreator.code: FutureContinuousChoiceQuestionCreator,
    PresentContinuousChoiceQuestionCreator.code: PresentContinuousChoiceQuestionCreator,
    FutureContinuousNegativeChoiceQuestionCreator.code: FutureContinuousNegativeChoiceQuestionCreator,
    FutureDualVideoQuestionCreator.code: FutureDualVideoQuestionCreator,
    FuturePerfectContinuousChoiceQuestionCreator.code: FuturePerfectContinuousChoiceQuestionCreator,
    FuturePerfectContinuousNegativeChoiceQuestionCreator.code: FuturePerfectContinuousNegativeChoiceQuestionCreator,
    GoingToFutureNegativeChoiceQuestionCreator.code: GoingToFutureNegativeChoiceQuestionCreator,
    PresentContinuousPartWordTypingQuestionCreator.code: PresentContinuousPartWordTypingQuestionCreator,
    PresentContinuousNegativePartWordTypingQuestionCreator.code: PresentContinuousNegativePartWordTypingQuestionCreator,
    PresentContinuousFullWordTypingQuestionCreator.code: PresentContinuousFullWordTypingQuestionCreator,
    PresentContinuousNegativeFullWordTypingQuestionCreator.code: PresentContinuousNegativeFullWordTypingQuestionCreator,
    PresentContinuousInterrogationPartWordTypingQuestionCreator.code: PresentContinuousInterrogationPartWordTypingQuestionCreator,
}


class CreatorNode:
    def __init__(self, question_creator: QuestionCreator):
        self.question_creator = question_creator
        self.next: QuestionCreator = None


class QuestionPack:
    def __init__(self, code: str, level_to_question_types: Dict[int, List[str]], level_to_master: int = None):
        self.code: str = code
        self.level_to_question_types: Dict[int, List[str]] = level_to_question_types
        self.level_to_master: int = len(level_to_question_types.keys())
        self._question_types: List[str] = None
        self._question_type_to_level: Dict[str, int] = None
        self._responsibility_chain: Dict[str, CreatorNode] = None

    @property
    def question_types(self) -> List[str]:
        if self._question_types is None:
            self._question_types = []
            for level, question_types in self.level_to_question_types.items():
                for question_type in question_types:
                    self._question_types.append(question_type)
        return self._question_types

    @property
    def question_type_to_level(self) -> Dict[str, int]:
        if self._question_type_to_level is None:
            self._question_type_to_level = {}
            for level, question_types in self.level_to_question_types.items():
                for question_type in question_types:
                    self._question_type_to_level[question_type] = level
        return self._question_type_to_level

    @property
    def responsibility_chain(self) -> Dict[str, CreatorNode]:
        """
        Create the responsability chain according to the question pack given
        in the constructor. The chain is a single linked list.
        """
        if self._responsibility_chain is None:
            self._responsibility_chain = {}
            levels = sorted(list(self.level_to_question_types.keys()), reverse=True)
            last = None
            for level in levels:
                questions = self.level_to_question_types[level]
                for index in range(len(questions)):
                    #  Get the current node in the chain
                    question_code = questions[index]
                    question_creator = question_type_to_creator[question_code]
                    self._responsibility_chain[question_code] = CreatorNode(
                        question_creator
                    )
                    #  Get the previous node and link it to the current one
                    if last:
                        last.next = self._responsibility_chain[question_code]
                    last = self._responsibility_chain[question_code]
        return self._responsibility_chain
