'''
Created on 12-Jul-2021

@author: bthakur
'''
import random
import inspect
import traceback
import re

import sympy
from xv.util import locatePath, FileSystemManager
from xv.util import MakoHelper
import pathlib

from bs4 import BeautifulSoup
import numpy as np

from xv.util import UtilClass

class MultiVariableHelper(UtilClass):
    
    _DEFULT_FILE_PATH = "xv_lib_resources/math/multi_variable_problems.html"

    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.file_path = self._init_file_path(**kwargs)
        
        self.problem_units = self._init_data()

        self.mako_helper = MakoHelper(verbose = True ) #self.verbose)
        pass

    def get_random_problem_unit(self):
        methods = [
            self.get_random_problem_unit_qty_price_cost,
            self.get_random_problem_unit_period_price_cost,
            self.get_random_problem_unit_qty_differential_cost,
            ]
        
        #method =  random.choice(methods[-1:])
        method =  random.choice(methods)
        
        return method()
        pass
        
            
    def get_random_problem_unit_qty_differential_cost(self):
        problem_type = 'qty_differential_cost'
        
        items = random.sample([
            'ice-cream', 
            'chocolate', 
            'pizza',
            'burger',
            'cold drink',
            ], 2)
        
        quntities = np.random.randint(1, 10, (2, 2)) 
        prices = np.random.randint(1, 10, (2, 1)) 
        
        costs = quntities * prices
        total_cost =  sum(costs)
        
        cost_scenario1 = costs[0][0] + costs[1][0]
        cost_scenario2 = cost_scenario1 + costs[0][1]
        cost_scenario3 = cost_scenario2 + costs[1][1]
        
        delta_costs = [
            cost_scenario2 - cost_scenario1,
            cost_scenario3 - cost_scenario2
            ]
        
        cost_scenarios = [cost_scenario1,
                          cost_scenario2,
                          cost_scenario3,
                          ]

        quntities_scenarios = [
                                [quntities[0][0], 
                                 quntities[1][0] ],
                                
                                [quntities[0][0] + quntities[0][1], 
                                 quntities[1][0] ],
                                
                                [quntities[0][0] + quntities[0][1], 
                                 quntities[1][0] + quntities[1][1] ],
                               ]
        
        currency = r'\$'
        
        data = {
            'items': items,
            'quntities': quntities,
            'prices': prices,
            'cost_scenarios': cost_scenarios,
            'quntities_scenarios': quntities_scenarios,
            'delta_costs': delta_costs,
            'total_cost': total_cost,
            'costs': costs,
            'currency': currency
            }
        
        problem_unit = self.get_problem_unit(problem_type = problem_type, 
                                             **data)
        return problem_unit
        pass
    
    def get_random_problem_unit_qty_price_cost(self):
        problem_type = 'qty_price_cost'

        items = random.sample([
            'ice-cream', 
            'chocolate', 
            'pizza',
            'burger',
            'cold drink',
            ], 2)
        
        quntities = [random.randint(1, 9), random.randint(1, 9)]
        prices = [random.randint(1, 9), random.randint(1, 9)]
        
        costs = [a * b for a, b in zip(quntities, prices)]
        total_cost =  sum(costs)
        currency = r'\$'
        
        data = {
            'items': items,
            'quntities': quntities,
            'prices': prices,
            'total_cost': total_cost,
            'costs': costs,
            'currency': currency
            }
        
        
        problem_unit = self.get_problem_unit(problem_type = problem_type, 
                                             **data)
        return problem_unit
        pass
    
    def get_random_problem_unit_period_price_cost(self):
        problem_type = 'period_price_cost'

        items = random.sample([
            'ice-cream', 
            'chocolate', 
            'pizza',
            'burger',
            'cold drink',
            ], 2)
        
        period_units, conv_factor = random.choice([
            [['hour', 'day'], 24],
            [['day', 'fortnight'], 15],
            [['day', 'week'], 7],
            [['month', 'year'], 12],
            ])
        
        period = random.randint(2, 9)
        
        quntities = [random.randint(1, 9), random.randint(1, 9)]
        prices = [random.randint(1, 9), random.randint(1, 9)]
        
        costs =  [a * b for a, b in zip(quntities, prices)]
        item_wise_costs = [costs[0] * conv_factor * period,
                           costs[1] * period]
        total_cost = sum(item_wise_costs)
        diff_in_costs = item_wise_costs[0] - item_wise_costs[1]


        currency = random.choice([r'\$', 'Rs.'])
        
        data = {
            'currency': currency,
            'costs': costs,
            'item_wise_costs': item_wise_costs,
            'diff_in_costs': diff_in_costs,
            'total_cost': total_cost,
            'items': items,
            'period_units': period_units,
            'period': period,
            'conv_factor': conv_factor,
            }
        
        
        problem_unit = self.get_problem_unit(problem_type = problem_type, 
                                             **data)
        return problem_unit
        pass
    
    
    def get_problem_unit(self, problem_type = None, **kwargs):
        if not self.problem_units:
            self._log("No data in problem_units")
            return None
            
        if problem_type:
            problem_units = []
            for problem_unit in self.problem_units:
                if not problem_unit.has_attr("class"):
                    continue
                if not problem_type in problem_unit.get("class"):
                    continue
                problem_units.append(problem_unit)
                pass
        else:
            problem_units = self.problem_units
            pass
            
        if not problem_units:
            self._log(f"No problem_units with class '{problem_type}' found.")
            return None
        
        problem_unit = random.choice(problem_units)
    
        qass = problem_unit.findAll('div', 
                                    attrs={'class':'question_answer_solution'})
        if not qass:
            self._log("div with class 'question_answer_solution' not found")
            return None

        self._log(f"len(qass): {len(qass)}")

        qas = random.choice(qass)
        
        problem_statements = problem_unit.findAll('div', attrs={'class':'problem_statement'})
        if problem_statements:
            problem_statement = random.choice(problem_statements)
        else:
            problem_statement = ""
            pass
        
        question = qas.find('div', attrs={'class':'question'})
        if not question:
            self._log("div with class 'question' not found")
            return None

        answer = qas.find('div', attrs={'class':'answer'})
        if not answer:
            self._log("div with class 'answer' not found")
            return None

        solution = qas.find('div', attrs={'class':'solution'})
        if not solution:
            self._log("div with class 'solution' not found")
            return None

        if problem_statement:
            problem_statement = self._render_html_node(problem_statement, **kwargs)
            
        question = self._render_html_node(question, **kwargs)
        answer = self._render_html_node(answer, **kwargs)
        solution = self._render_html_node(solution, **kwargs)

        result = {
            'problem_statement': problem_statement,
            'question': question,
            'answer': answer,
            'solution': solution
            }

        return result
        pass

    
    
    def _render_html_node(self, html_node, **kwargs):
        html_text = " ".join(line.strip() for line in f"{html_node}".split("\n"))
        rendered_html = self.mako_helper.render_text(html_text, **kwargs)
        return rendered_html
        pass
    
    
    def _init_data(self): 
        try:
            soup = self._get_soup()
            if not soup:
                self._log("Soup could not be loaded")
                return None
        
            problem_units = soup.findAll('div', attrs={'class':'problem_unit'})
            if not problem_units:
                self._log("div with class 'problem_unit' not found")
                return None

            self._log(f"len(problem_units): {len(problem_units)}")
            
            return problem_units
        
        except Exception as e:
            sError = f"""Error {self.__class__.__name__}.{inspect.stack()[0][3]}: {e}
            """
            self._log(sError)
            self._log(traceback.format_exc())
        return None
        
    def _get_soup(self): 
        try:
            if self.file_path is None:
                self._log("The file path is None")
                return None
    
            encoding_type = "utf8"
            soup = BeautifulSoup(open(self.file_path, 
                                      'r', 
                                      encoding = encoding_type,
                                      errors ='replace'), 
                                 features="lxml")
            return soup
        except Exception as e:
            sError = f"""Error {self.__class__.__name__}.{inspect.stack()[0][3]}: {e}
            self.file_path = {self.file_path}
            """
            self._log(sError)
            self._log(traceback.format_exc())
        return None

    def _init_file_path(self, **kwargs):
        file_path = kwargs.get('file_path', None)
        if file_path is None:
            file_path = self.__class__._DEFULT_FILE_PATH

        from xv.util.data import Repository
        return Repository.FIND_EXACT_FILE(file_path, verbose = self.verbose)
        pass

    pass
#class MultiVariableHelper:
