'''
Created on 01-Apr-2021
@author: rishi_priyansh
'''
import random
import inspect
import traceback
from sympy import (symbols, Symbol)

from xv.km.util import latex_fraction, latex_atom
from ...helper import BaseHelper

from xv.km.managers import BaseManager
from xv.km.kelements import KProblemTemplate
from os.path import os
        
#_simple_physics
# SimplePhysics

class   SimplePhysics(BaseManager):
    '''
    SimplePhysics
    Example:
        ke = SimplePhysics()
        ke.getRandomProblem()
        ke.getRandomProblem(problem_type = 0)
        ...
        
        ke.printProblem()
        ke.printAnswer()
        ke.printSolution()
        
        ke.printProblemTypes()
        
    '''    
    _OPR_TYPE_COUNT = 10
    
    def __new__(cls, *args, **kwargs):
        instance = super(SimplePhysics, cls).__new__(cls, *args, **kwargs)
        for base_class in SimplePhysics.__bases__:
            base_class.__init__(instance)
        return instance
    
    def __init__(self, *args, **kwargs):
        pass
    
    def _init_problem_types(self, *args, **kwargs):
        self._append_problem_types([
            '_problem_the_three_switches',
            '_problem_two_closed_boxes',
            '_problem_bullet_fired_straight_up',
            '_problem_categories_van_physics_illinois_edu',
            '_problem_question_links_van_physics_illinois_edu',
            ])
        pass
            
    def _problem_the_three_switches(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        The Three Switches
        <br/>
        Downstairs in a house are three identical on-off switches. 
        One of them controls the lamp in the attic. 
        The puzzle is to work out which switch controls the lamp.
        
        The rules are as follows. You are allowed to manipulate 
        the switches all you like, and then you are allowed only one trip to the attic. 
        How do you do it?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False)
        
        soln_s = r"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = fr"""
        <a target = "_blank"  href = "https://www.theguardian.com/science/2015/jun/22/did-you-solve-it-are-you-smarter-than-jo-nesb0-monday-puzzle-solution">See answer</a>
        
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    
            
    def _problem_two_closed_boxes(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        Two closed boxes, A and B, are on a table in front of you. A contains £1,000. B contains either nothing or £1 million. You don’t know which. You have two options:
        <br/>
        1. Take both boxes.
        <br/>
        2. Take box B only.
        <br/>
        <br/>
        You keep the contents of the box/boxes you take, and your aim is to get the most money.
        <br/>
        <br/>
        But here’s the thing. The test was set by a Super-Intelligent Being, who has already made a prediction about what you will do. If Her prediction was that you would take both boxes, She left B empty. If Her prediction was that you would take B only, She put a ₤1 million cheque in it.
        <br/>
        <br/>
        Before making your decision, you do your due diligence, and discover that the Super-Intelligent Being has never made a bad prediction. She predicted Leicester would win the Premier League, the victories of Brexit and Trump, and that Ed Balls would be eliminated yesterday from Strictly Come Dancing. She has correctly predicted things you and others have done, including in situations just like this one, never once getting it wrong. It’s a remarkable track-record. So, what do you choose? Both boxes or just box B?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False)
        
        soln_s = r"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = fr"""
        <a target = "_blank"  href = 
        "https://www.theguardian.com/science/alexs-adventures-in-numberland/2016/nov/28/newcombs-problem-divides-philosophers-which-side-are-you-on"
        >See answer</a>
        """.replace("\n", "")
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    
    def _problem_bullet_fired_straight_up(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')

        problem_s = fr"""
        If you shot a round bullet straight up (Vertically), 
        is it true that when the bullet falls back to the same 
        point where it was shot, it will have the same velocity(speed) 
        as when it was fired?
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html',
                                    add_html_line_break = False)
        
        soln_s = r"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = fr"""
        <a target = "_blank"  href = 
        "https://van.physics.illinois.edu/qa/listing.php?id=2101&t=if-you-shoot-a-bullet-straight-up..."
        >See answer</a>
        """.replace("\n", "")
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _problem_categories_van_physics_illinois_edu(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        category_links = self._get_illinois_category_links()
        
        links_str = [f"""{idx}. <a target="_blank" href="{link_url}" >{link_text}</a>""" 
                     for idx, (link_url, link_text) in enumerate(category_links)]
        
        links_str = "\n".join(links_str)
        problem_s = fr"""
        {links_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        soln_s = r"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    
    def _problem_question_links_van_physics_illinois_edu(self, *args, **kwargs):
        problemTemplate = KProblemTemplate()
        problemTemplate.problem_type = kwargs.get('problem_type')
        
        category_idx = kwargs.get('category_idx', None)
        
        category_links = self._get_illinois_category_links()
        if not category_idx is None:
            category_url, category = category_links[category_idx]
        else:
            category_url, category = random.choice(category_links)
            
        links = self._get_illinois_question_links(category_url)
        
        links_str = [f"""{idx}. <a target="_blank" href="{link_url}" >{link_text}</a>""" 
                     for idx, (link_url, link_text) in enumerate(links)]
        
        links_str = "\n".join(links_str)

        problem_s = fr"""
        <h2>{category}</h2>
        {links_str}
        """
        problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        if category_idx is None:
            problem_s = fr"""
            <h2>Note:</h2>
            Pass category_idx to get a particular category.
            Get list of category from previous problem type
            
            category_idx = 1
            """
            problemTemplate.add_problem(problem_s.strip(), 'text/html')
        
        
        soln_s = r"""
        """
        problemTemplate.add_solution(soln_s.strip(), 'text/html')
        
        answer_s = fr"""
        """
        problemTemplate.add_answer(answer_s.strip(), 'text/html')
        
        return problemTemplate
    
    def _load_url(self, page_url):
        import requests
        import inspect
        from bs4 import BeautifulSoup as BS
        try: 
            html = requests.get(page_url, verify=True, timeout=10)
            soup = BS(html.content, "lxml")
            return soup
        except Exception as e:
            sError = f"""Error {self.__class__.__name__}.{inspect.stack()[0][3]}:
            page_url = {page_url}
            {e}"""
            print(sError)
    
        return None

    def _get_illinois_category_links(self):
        base_url = "https://van.physics.illinois.edu/qa"
        page_url = f"{base_url}/"
        
        soup = self._load_url(page_url)
        if not soup:
            return None
        
        links = soup.findAll('a')
        
        category_links = []
        for a in links:
            if not a.has_attr("href"):
                continue
                
            href = a['href']
            if not "subcategory.php?sub=" in href:
                continue
            
            link_url = f"{base_url}/{href}"
            link_text = a.text.strip()
            category_links.append([link_url, link_text])
            pass

        return category_links

    def _get_illinois_question_links(self, category_url):
        base_url = "https://van.physics.illinois.edu/qa"
        
        soup = self._load_url(category_url)
        if not soup:
            return None
        
        subcategory = soup.find('div', {'class': 'subcategory'})
        links = subcategory.findAll('a')
        
        category_links = []
        for a in links:
            if not a.has_attr("href"):
                continue
                
            href = a['href']
            
            link_url = f"{base_url}/{href}"
            link_text = a.text.strip()
            category_links.append([link_url, link_text])
            pass

        return category_links
