'''
Created on 01-Apr-2021
@author: bthakur
'''
import os
import pathlib
import json

import random
import inspect
import traceback


from xv.util.data import Repository
from xv.util import toIntOrFloat, locatePath
from xv.km.qa import QaHelper


from ..helper import BaseHelper
from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate


class QaManager(BaseManager):
    '''
    QaManager
    Example:
        ke = QaManager()
        ke.getRandomProblem()

        ke.print_qa_files()
        ke.load_qa_file(2)
        ke.print_chapters()

        ke.getRandomProblem(problem_type = 0)
        ke.getRandomProblem(problem_type = 1, chapter_index = 2, max_count = 4)
        ke.getRandomProblem(problem_type = 3, search = ["force", "speed"])
        ke.getRandomProblem(problem_type = 4, search = ["force", "newton"], max_count = 4)
        ...

        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()

        ke.printProblemTypes()

    '''
    #_QA_ROOT_FOLDER = 'resources/ncert'
    _QA_ROOT_FOLDER = 'xv_lib_resources/math/ncert'


    def __new__(cls, *args, **kwargs):
        instance = super(QaManager, cls).__new__(cls, *args, **kwargs)
        for base_class in QaManager.__bases__:
            base_class.__init__(instance, *args, **kwargs)
        return instance

    def __init__(self, *args, **kwargs):

        Repository() #init default path

        self.base_helper = BaseHelper(**kwargs)
        self.qa_files = self._init_qa_files()
        self._qaHelper = None
        pass

    def get_qa_helper(self):
        if self._qaHelper is None:
            self._load_qa_file()
        return self._qaHelper



    def _init_qa_files(self):
        folder_name = QaManager._QA_ROOT_FOLDER

        repository = Repository(verbose = self.verbose)

        qa_root_folder = repository.get_path(name = folder_name,
                                             search_type = 'folder',
                                             part_match = False)
        if not qa_root_folder:
            self._log(f"Failed to locate folder_name = {folder_name}")
            return None

        qa_files =  QaHelper.LIST_FILES(qa_root_folder)
        qa_files = sorted(qa_files, reverse=True)
        return qa_files


    def get_qa_files(self):
        qa_files_str = [qa_file.split("/")[-1]
            for qa_file in self.qa_files]
        return qa_files_str


    def print_qa_files(self):
        qa_files_str = [str(i+1) + ". " +  qa_file
            for i, qa_file in enumerate(self.get_qa_files())]

        qa_files_str = "\n".join(qa_files_str)
        print(qa_files_str)
        print("""To lood file:
        ke.load_qa_file('ncert/ncert-solutions-for-class-9-science.json')
        """)

    def load_qa_file(self, file_path = None):
        if isinstance(file_path, int):
            file_path = self.qa_files[file_path - 1]

        loaded_file_path = self._load_qa_file(file_path)
        if loaded_file_path is None:
            print(f"failed to load {file_path}")
            return None

        loaded_file_path = loaded_file_path.split("/")[-1]
        print(f"Loaded {loaded_file_path}")

        print(f"The chapters are:")
        self.print_chapters()
        pass

    def _get_qa_file_full_path(self, file_path):
        file_path = file_path.replace("\\", "/")
        for p in self.qa_files:
            if p.endswith(file_path):
                return p
        return None

    def _load_qa_file(self, file_path = None):
        if file_path is None:
            file_path = self.qa_files[0]

        if not os.path.isfile(file_path):
            file_path = self._get_qa_file_full_path(file_path)

        if file_path is None:
            return None

        self._qaHelper = QaHelper(file_path = file_path, verbose = self.verbose)
        return file_path
        pass


    def print_chapters(self):
        chapters = self.get_qa_helper().get_chapters()
        chapters = [f"{i}. {c} ({q_count})" for i, (c, q_count) in enumerate(chapters)]
        chapters_str = '\n'.join(chapters)
        print(chapters_str)

    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_list_qa_files',
            '_problem_list_qa_of_a_chapter',
            '_problem_random_question',
            '_problem_search_first_question',
            '_problem_search_questions',
            ])
        pass

    def _problem_list_qa_files(self, *args, **kwargs):

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        qa_files_str = [qa_file.split("/")[-1]
            for qa_file in self.qa_files]

        qa_files_str = "<ol><li>" + "</li><li>".join(qa_files_str) + "</li></ol>"

        problem_s = f"""
        List question and answer files
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        Note: By default, first file is loaded. To load another file, used name or number:
        ke.load_qa_file(1) , or
        ke.load_qa_file('ncert/ncert-solutions-for-class-9-science.json')

        {qa_files_str}

        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {qa_files_str}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

    def _problem_list_qa_of_a_chapter(self, *args, **kwargs):

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        chapter_index = kwargs.get('chapter_index', None)
        max_count = kwargs.get('max_count', None)

        #chapters = self.get_qa_helper().get_chapters()
        #chapters_str = '<ol start="0"><li>' + "<br/></li><li>".join(chapters) + "</li></ol>"

        random_qs, chapter_index = self.get_qa_helper().get_qa_of_a_chapter(
                                                            chapter_index = chapter_index,
                                                            max_count = max_count)

        if random_qs is None:
            problem_s = f"No questions found for chapter {chapter_index}"
            problemTemplate.add_problem(problem_s.strip(), 'text/html')
            return problemTemplate

        (qas_str,
         questions_str,
         answers_str) = self.get_qa_helper().get_questions_answers_html(random_qs)

        problem_s = f"""
        Note:
        1. To see questions of a chapter, pass parameter chapter_index
        \tke.getRandomProblem(problem_type = 1, chapter_index = 5)
        \tYou can also pass max_count to restrict the number of questions.
        \tke.getRandomProblem(problem_type = 1, chapter_index = 5, max_count = 4)

        2. To see all chapters:
        ke.print_chapters()

        <h2>Chapter: {chapter_index}</h2>
        {questions_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <h2>Chapter: {chapter_index}</h2>
        {qas_str}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {answers_str}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


    def _problem_random_question(self, *args, **kwargs):

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        random_q = self.get_qa_helper().get_random_question()
        question = "\n".join(random_q.get('q'))
        answer = "\n".join(random_q.get('a'))

        problem_s = f"""
        {question}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        {question}

        {answer}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {answer}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

    def _problem_search_first_question(self, *args, **kwargs):

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        search = kwargs.get('search')

        if isinstance(search, str):
            search_str = search
        else:
            search_str = ", ".join(search)

        random_q = self.get_qa_helper().search(search,
                                        search_question = True,
                                        search_answer = True,
                                        find_first = True
                                        )
        question = random_q.get('q', None)
        answer = random_q.get('a', None)

        if not question is None:
            question = "\n".join(question)

        if not answer is None:
            answer = "\n".join(answer)

        problem_s = f"""
        <b>Random questions related to {search_str}</b>

        {question}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Random questions related to {search_str}</b>

        {question}

        {answer}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {answer}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

    def _problem_search_questions(self, *args, **kwargs):

        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        search = kwargs.get('search')

        if isinstance(search, str):
            search_str = search
        else:
            search_str = ", ".join(search)

        random_qs = self.get_qa_helper().search(search,
                                        search_question = True,
                                        search_answer = True,
                                        find_first = False
                                        )

        (qas_str,
         questions_str,
         answers_str) = self.get_qa_helper().get_questions_answers_html(random_qs)

        problem_s = f"""
        <b>Questions related to {search_str}</b>

        {questions_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        <b>Questions related to {search_str}</b>

        {qas_str}
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        {answers_str}
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate


    def _sample(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = f"""
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')

        soln_s = f"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')

        answer_s = f"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')

        return problemTemplate

