'''
Created on 20-Jan-2022

@author: bthakur
'''

import inspect
import traceback
import random
import numpy as np


from xv.util.htmlutil import (join_with_comma, get_decimal_numbers, 
                              make_decimals_similar, decimal_sums_data, 
                              round_decimal_result, get_option_and_answer_statements,
                              
                              )

from xv.util.htmlutil import (get_random_html_shape,
                              int_to_html_shapes,
                              int_to_html_shapes_crossed,
                              get_nums_prod_shapes,
                              get_nums_division_shapes,
                              )


from sympy import (Mul, Add, latex, Symbol,
                   Rational,
                   )
import sympy as sp

from xv.km.util import wrap_in_latex
from xv.km.kelements import KProblemTemplate

from xv.util import UtilClass, html_list, list_to_str

# _integer_properties_helper
# IntegerPropertiesHelper


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

    def get_additive_inverse_int(self, *args, **kwargs):
        '''
        '''
        expr = random.randint(-10, 10)
        latex_expr = latex(expr)
        return self._get_additive_inverse_expr(expr, latex_expr, *args, **kwargs)
        pass

    def get_additive_inverse_int_expr(self, *args, **kwargs):
        '''
        '''
        terms = []
        latex_expr = []
        
        count = random.randint(3, 7)
        
        while len(terms) < count:
            num = random.randint(-10, 10)
            terms.append(num)
            if num >= 0:
                latex_num = f"+ {latex(num)}"
            else:
                latex_num = f"- {latex(abs(num))}"
            latex_expr.append(latex_num)
            pass
        
        latex_expr = " ".join(latex_expr)
        expr = Add(*terms)
        return self._get_additive_inverse_expr(expr, latex_expr, *args, **kwargs)
        pass


    def _get_additive_inverse_expr(self, expr, latex_expr, *args, **kwargs):
        '''
        '''
        
        correct_option = - expr
        
        all_options = [correct_option - 1, 
                       correct_option - 2,
                       correct_option + 1, 
                       correct_option + 2,
                       Rational(1, expr),
                       Rational(1, - expr),
                       1,
                       0,
                       expr,
                       ]

        incorrect_options = [item for item in all_options 
                             if item != correct_option
                             ]
        incorrect_options = list(set(incorrect_options))
        options = random.sample(incorrect_options, 3)
        options.append(correct_option)

        option_s, answer_s = get_option_and_answer_statements(options, 
                                                              correct_option, 
                                                              apply_latex = True)

        prob_stmts = []

        prob_stmt = f"""
        The additive inverse of ${latex_expr}$ is
        """
        prob_stmts.append(prob_stmt.replace("\n", " ").strip())
        

        prob_stmt = random.choice(prob_stmts)
        prob_s = f"""
        {prob_stmt}
        {option_s}
        """
        prob_s = prob_s.strip()

        soln_stmts = []
        
        soln_stmt = f"""
        When additive inverse of a number is the number multiplied by $-1$.
        When the number and its additive inverse are added together, the result is zero.
        
        """
        soln_stmts.append(soln_stmt.replace("\n", " ").strip())
        
        if not isinstance(expr, int):
            soln_stmt = f"""
            $\\displaystyle 
            \\text{{ the expression }}  \\\\ \\\\
            = {latex_expr} \\\\ \\\\
            = {latex(expr)} 
            $
            """
            soln_stmts.append(soln_stmt.strip())
            pass
        
        soln_stmt = f"""
        $\\displaystyle \\implies
        \\text{{ The additive inverse of }} {latex_expr} \\\\ \\\\
        = -1 \\cdot {latex(expr)} \\\\ \\\\
        = {latex(correct_option)} 
        $
        """
        soln_stmts.append(soln_stmt.strip())

        soln_stmt = f"""
        Let us check now:
        
        $\\displaystyle 
        \\text {{ (the number) }} + \\text{{ (its additive inverse) }} \\\\ \\\\
        = {latex(expr)} + {latex(correct_option)}  \\\\ \\\\
        = 0
        $
        """
        soln_stmts.append(soln_stmt.strip())
        
        
        soln_s = "\n\n".join(soln_stmts).strip()

        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }

        return result
        pass
  
  
    def get_multiplicative_inverse_int(self, *args, **kwargs):
        '''
        '''
        expr = random.randint(-10, 10)
        latex_expr = latex(expr)
        return self._get_multiplicative_inverse_expr(expr, latex_expr, *args, **kwargs)
        pass

    def get_multiplicative_inverse_int_expr(self, *args, **kwargs):
        '''
        '''
        terms = []
        latex_expr = []
        
        count = random.randint(3, 7)
        
        while len(terms) < count:
            num = random.randint(-10, 10)
            terms.append(num)
            if num >= 0:
                latex_num = f"+ {latex(num)}"
            else:
                latex_num = f"- {latex(abs(num))}"
            latex_expr.append(latex_num)
            pass
        
        latex_expr = " ".join(latex_expr)
        expr = Add(*terms)
        return self._get_multiplicative_inverse_expr(expr, latex_expr, *args, **kwargs)
        pass

    def _get_multiplicative_inverse_expr(self, expr, latex_expr, *args, **kwargs):
        '''
        '''
        seed_number = 1 / expr 
        
        all_options = [seed_number - 1, 
                       seed_number - 2,
                       seed_number + 1, 
                       seed_number + 2,
                       Rational(1, expr),
                       Rational(1, - expr),
                       1,
                       0,
                       expr,
                       ]
        
        if expr == 0:
            correct_option = "Does not exist."
        else:
            correct_option = Rational(1, expr)
            

        incorrect_options = [item for item in all_options 
                             if item != correct_option
                             ]
        incorrect_options = list(set(incorrect_options))
        options = random.sample(incorrect_options, 3)
        options.append(correct_option)

        option_s, answer_s = get_option_and_answer_statements(options, 
                                                              correct_option, 
                                                              apply_latex = True)

        prob_stmts = []

        prob_stmt = f"""
        The multiplicative inverse of ${latex_expr}$ is
        """
        prob_stmts.append(prob_stmt.replace("\n", " ").strip())
        

        prob_stmt = random.choice(prob_stmts)
        prob_s = f"""
        {prob_stmt}
        {option_s}
        """
        prob_s = prob_s.strip()

        soln_stmts = []
        
        soln_stmt = f"""
        When multiplicative inverse of a number is $1$ divided by the number.
        When the number and its multiplicative inverse are multiplied together, the result is one.
        
        """
        soln_stmts.append(soln_stmt.replace("\n", " ").strip())
        
        if not isinstance(expr, int):
            soln_stmt = f"""
            $\\displaystyle 
            \\text{{ the expression }}  \\\\ \\\\
            = {latex_expr} \\\\ \\\\
            = {latex(expr)} 
            $
            """
            soln_stmts.append(soln_stmt.strip())
            pass
        
        if expr == 0:
            soln_stmt = f"""
            We cannot divide any number by ${latex(expr)}$, 
            so there is no multiplicative inverse of ${latex(expr)}$.
            """
            soln_stmts.append(soln_stmt.replace("\n", " ").strip())
            pass
        else:
            
            soln_stmt = f"""
            $\\displaystyle \\implies
            \\text{{ The multiplicative inverse of }} {latex_expr} \\\\ \\\\
            = \\frac {{ 1 }} {{ {latex(expr)} }}  \\\\ \\\\
            = {latex(correct_option)} 
            $
            """
            soln_stmts.append(soln_stmt.strip())
            
            soln_stmt = f"""
            Let us check now:
            
            $\\displaystyle 
            \\text {{ (the number) }} \\cdot \\text{{ (its multiplicative inverse) }} \\\\ \\\\
            = {latex(expr)} \\cdot {latex(correct_option)}  \\\\ \\\\
            = 1
            $
            """
            soln_stmts.append(soln_stmt.strip())
            
            pass

        soln_s = "\n\n".join(soln_stmts).strip()
        
        result = {
            'prob_s': prob_s.strip(),
            'soln_s': soln_s.strip(),
            'answer_s': answer_s.strip(),
            }

        return result
        pass
    
  
    pass
#class IntegerPropertiesHelper:
