'''
Created on 12-Jul-2021

@author: bthakur
'''
import random
import inspect
import traceback   #        {inspect.stack()[0][3]}




import re
from sympy import (Eq, Symbol, symbols, sqrt, latex,
                   Rational, solve, log, nsimplify, E, exp,  
                   sin, cos, I, series, pi)
from sympy.abc import theta
import sympy

from ....util import LatexEquation

from xv.km import CustomLogarithm as Log
from xv.km.util import latex_fraction, latex_exponent

from xv.util import UtilClass

class ModellingTwoDigitsHelper(UtilClass):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        pass


    def get_random_model(self, **kwargs):
        methods = [self.get_model_diff,
                   self.get_model_less_than_multiple,
                   self.get_model_more_than_multiple,
                   self.get_model_multiple,
                   self.get_model_sum,
                   ]
        
        method = random.choice(methods)
        var_names = kwargs.get('var_names', None)
        var_vals = kwargs.get('var_vals', None)
        
        x, y = symbols('x, y')
        if var_names is None:
            var_names = {x: 'ones digit',
                         y: 'tens digit',
                         }
            kwargs['var_names'] = var_names
        
        if var_vals is None:
            x_val = random.randint(1, 8)
            y_val = 9 - x_val
            var_vals = {x: x_val,
                         y: y_val,
                         }
            kwargs['var_vals'] = var_vals

        solutions = {
            x: x_val,
            y: y_val, 
            }
        
        
        random_model = method(**kwargs)
        latex_eq = random_model.get("latex_eq", None)
        
        eq = latex_eq.eq
        
        eqs_str = f"""$\\displaystyle {latex(latex_eq)}$ """
 
        statement_header = "Convert into mathematical model."
        statement_footer = ""
        
        addl_dict = {
            'statement_header': statement_header,
            'statement': random_model.get("statement", "SOMETHING WENT WRONG"),
            'statement_footer': statement_footer,
            'var_names': var_names,
            'latex_eqs': [latex_eq],
            'eqs_str': eqs_str,
            'var_names': var_names,
            'var_vals': var_vals,
            'solutions': solutions,
            }
        
        random_model.update(addl_dict)
    
        var_names_str = [f"${latex(k)}: {latex(v)}$" for k,v in var_names.items()]
        var_names_str = "\n".join(var_names_str)
        
        solutions_str = [f"${latex(k)}: {latex(v)}$" for k,v in solutions.items()]
        solutions_str = "\n".join(solutions_str)
        
        prob_s = f"""
        {random_model['statement_header']}
        {random_model['statement']}
        {random_model['statement_footer']}
        """
                
        soln_s = f"""
        <b>Let:</b>
        {var_names_str}
        
        <b>Equations:</b>
        {random_model['eqs_str']}
        
        <b>Solving the equations:</b>
        {solutions_str}
        """
        
        answer_s = f"""
        {solutions_str}
        """
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }
        
        return result
        pass

    
    def get_model_sum(self, var_names = None, var_vals = None):
        x, y = var_names.keys()
        x_label, y_label = var_names.values()
        x_val, y_val = var_vals.values()
        
        statement1 = f"""
        The sum of both digits is {x_val + y_val}. 
        """

        statement2 = f"""
        The sum of {x_label} and {y_label} is {x_val + y_val}. 
        """
        
        statement = random.choice([statement1, 
                                   statement2,
                                   ])

        
        eq = Eq(x + y, x_val + y_val)
        latex_eq = LatexEquation.from_eq(eq)
        
        model = {
            'statement': statement.strip(),
            'eq': eq,
            'latex_eq': latex_eq
            }
        
        return model
        pass
    
    def get_model_diff(self, var_names = None, var_vals = None):
        x_val, y_val = var_vals.values()

        if x_val >= y_val:
            x, y = var_names.keys()
            x_label, y_label = var_names.values()
        else:
            y_val, x_val = var_vals.values()
            y, x = var_names.keys()
            y_label, x_label = var_names.values()
            
        statement1 = f"""
        {x_label.capitalize()} is {x_val - y_val} more than {y_label}.
        """

        eq1 = Eq(x, y + x_val - y_val)
        latex_eq1 = LatexEquation(f"{latex(x)}", 
                                 f"{latex(y)} + {x_val - y_val}", eq1)


        statement2 = f"""
        {y_label.capitalize()} is {x_val - y_val} less than {x_label}.
        """

        eq2 = Eq(y, x - (x_val - y_val))
        latex_eq2 = LatexEquation(f"{latex(y)}", 
                                 f"{latex(x)} - {x_val - y_val}", eq2)

        
        statement, eq, latex_eq = random.choice([(statement1, eq1, latex_eq1),
                                                 (statement2, eq2, latex_eq2),
                                                ])

        model = {
            'statement': statement.strip(),
            'eq': eq,
            'latex_eq': latex_eq
            }
        
        return model
        pass

    def get_model_multiple(self, var_names = None, var_vals = None):
        x_val, y_val = var_vals.values()

        if x_val >= y_val:
            x, y = var_names.keys()
            x_label, y_label = var_names.values()
        else:
            y_val, x_val = var_vals.values()
            y, x = var_names.keys()
            y_label, x_label = var_names.values()

        multiple = x_val // y_val
            
        statement1 = f"""
        {x_label.capitalize()} is {multiple} times the {y_label}.
        """

        eq1 = Eq(x , multiple * y)
        latex_eq1 = LatexEquation(f"{latex(x)}", 
                                 f"{multiple} * {latex(y)}", eq1)


        statement2 = f"""
        {y_label.capitalize()} is ${latex_fraction(1, multiple)}$ of {x_label}.
        """

        eq2 = Eq(y , Rational(1, multiple) * x)
        latex_eq2 = LatexEquation(f"{latex(y)}", 
                                 f"{Rational(1, multiple)} * {latex(x)}", eq2)

        
        statement3 = f"""
        The ratio of {x_label} to {y_label} is {multiple}.
        """

        eq3 = Eq(x / y , multiple)
        #latex_eq3 = LatexEquation(f"{latex_fraction(x, y)}", 
        #                         f"{multiple}", eq3)
        
        latex_eq3 = LatexEquation(x / y, 
                                 f"{multiple}", eq3)
        
        statement4 = f"""
        The ratio of {y_label} to {x_label} is 1:{multiple}.
        """

        eq4 = Eq(y / x , Rational(1, multiple))
        #latex_eq4 = LatexEquation(f"{latex_fraction(y, x)}", 
        #                         f"{latex_fraction(1, multiple)}", eq4)
        
        latex_eq4 = LatexEquation(y / x, 
                                 f"{Rational(1, multiple)}", eq4)
        
        statement, eq, latex_eq = random.choice([(statement1, eq1, latex_eq1),
                                                 (statement2, eq2, latex_eq2),
                                                 (statement3, eq3, latex_eq3),
                                                 (statement4, eq4, latex_eq4),
                                                ])
        
        model = {
            'statement': statement.strip(),
            'eq': eq,
            'latex_eq': latex_eq
            }
        
        return model
        pass
    
    
    def get_model_less_than_multiple(self, var_names = None, var_vals = None):
        x_val, y_val = var_vals.values()

        if x_val >= y_val:
            x, y = var_names.keys()
            x_label, y_label = var_names.values()
        else:
            y_val, x_val = var_vals.values()
            y, x = var_names.keys()
            y_label, x_label = var_names.values()

            
        multiple = (x_val // y_val) + 1
        less_by = y_val * multiple - x_val
            
        statement1 = f"""
        The {x_label} are {less_by} less than {multiple} times the {y_label}.
        """

        eq1 = Eq(x , multiple * y - less_by)
        latex_eq1 = LatexEquation(f"{latex(x)}", 
                                 f"{multiple} * {latex(y)} - {less_by}", eq1)
            
            

        statement2 = f"""
        The difference between {x_label} and {multiple} times the {y_label} is {less_by}.
        """
        
        eq2 = Eq(x - multiple * y, less_by)
        latex_eq2 = LatexEquation(f"{latex(x)} - {multiple} * {latex(y)}", 
                                 f"{less_by}", eq2)
            

        statement3 = f"""
        The {x_label} are fewer by {less_by} than {multiple} times the {y_label}.
        """

        eq3 = Eq(x , multiple * y - less_by)
        latex_eq3 = LatexEquation(f"{latex(x)}", 
                                 f"{multiple} * {latex(y)} - {less_by}", eq3)
            
            
        statement4 = f"""
        The {multiple} times {y_label} is {less_by} more than the {x_label}.
        """

        eq4 = Eq(multiple * y, x + less_by)
        latex_eq4 = LatexEquation(f"{multiple} * {latex(y)}", 
                                 f"{latex(x)} + {less_by}", eq4)
            
            
        statement, eq, latex_eq = random.choice([(statement1, eq1, latex_eq1),
                                                 (statement2, eq2, latex_eq2),
                                                 (statement3, eq3, latex_eq3),
                                                 (statement4, eq4, latex_eq4),
                                                ])
        

        model = {
            'statement': statement.strip(),
            'eq': eq,
            'latex_eq': latex_eq
            }
        
        return model
        pass
    
    def get_model_more_than_multiple(self, var_names = None, var_vals = None):
        x_val, y_val = var_vals.values()

        if x_val >= y_val:
            x, y = var_names.keys()
            x_label, y_label = var_names.values()
        else:
            y_val, x_val = var_vals.values()
            y, x = var_names.keys()
            y_label, x_label = var_names.values()

            
        multiple = (x_val // y_val) 
        more_by = x_val - y_val * multiple
            
        statement1 = f"""
        The {x_label} are {more_by} more than {multiple} times the {y_label}.
        """

        eq1 = Eq(x , multiple * y + more_by)
        latex_eq1 = LatexEquation(f"{latex(x)}", 
                                 f"{multiple} * {latex(y)} + {more_by}", eq1)
            

        statement2 = f"""
        The {x_label} exceed {multiple} times the {y_label} by {more_by}.
        """

        eq2 = Eq(x , multiple * y + more_by)
        latex_eq2 = LatexEquation(f"{latex(x)}", 
                                 f"{multiple} * {latex(y)} + {more_by}", eq2)
            
            
        
        statement3 = f"""
        The difference between {x_label} and {multiple} times the {y_label} is {more_by}.
        """
        
        eq3 = Eq(x - multiple * y, more_by)
        latex_eq3 = LatexEquation(f"{latex(x)} - {multiple} * {latex(y)}", 
                                 f"{more_by}", eq3)
            
        
        statement4 = f"""
        There are {more_by} more {x_label} than {multiple} times the {y_label}.
        """

        eq4 = Eq(x , multiple * y + more_by)
        latex_eq4 = LatexEquation(f"{latex(x)}", 
                                 f"{multiple} * {latex(y)} + {more_by}", eq4)
            
            

        statement5 = f"""
        {multiple} times the {y_label} are {more_by} fewer than {x_label}.
        """

        eq5 = Eq(multiple * y, x- more_by)
        latex_eq5 = LatexEquation(f"{multiple} * {latex(y)}", 
                                 f"{latex(x)} - {more_by}", eq5)
            
            
        
        statement, eq, latex_eq = random.choice([(statement1, eq1, latex_eq1),
                                                 (statement2, eq2, latex_eq2),
                                                 (statement3, eq3, latex_eq3),
                                                 (statement4, eq4, latex_eq4),
                                                 (statement5, eq5, latex_eq5),
                                                ])
        

        model = {
            'statement': statement.strip(),
            'eq': eq,
            'latex_eq': latex_eq
            }
        
        return model
        pass
    

    pass
#class ModellingTwoDigitsHelper:
