import re
import requests
from ._utils import BasePage, float_or_none
from lxml import etree
from datetime import datetime

class CompetitionPage(BasePage):

    BASE_URL = "http://www.betexplorer.com"
    URL_TEMPLATE = BASE_URL + "/soccer/{region}/{competition}/"

    def __init__(self, data):
        data = data.replace(r'&nbsp;', " ")
        self.tree = etree.HTML(data)
        super().__init__(data)

    @classmethod
    def get_url(cls, region, competition):
        return cls.URL_TEMPLATE.format(region=region, competition=competition)

    @property
    def matches_ids(self):
        stage_url_template = self.BASE_URL \
                             + self.tree.xpath('//*[@id="location"]/li[3]/a[3]')[0].get("href") \
                             + "results/?stage={stage_id}"
        # Find stage ids
        stage_ids = re.findall(r'\?stage=(.+?)"', self.data)
        # Go through all stage pages
        for stage_id in stage_ids:
            stage_url = stage_url_template.format(stage_id=stage_id)
            # Request made to retrieve the HTML for a given stage
            # TODO: should be avoided maybe ?
            res = requests.get(stage_url)
            tree = etree.HTML(res.text)
            matches = tree.xpath('//tbody[@id="leagueresults_tbody"]')[0]
            for match in matches:
                if match[0].tag == "td":
                    href = match[0][0].get("href")
                    m = re.match(r'\.\./matchdetails\.php\?matchid=(?P<id>.+)',
                                 href)
                    yield m.group("id")


class MatchPage(BasePage):

    URL_TEMPLATE = "http://www.betexplorer.com/soccer/europe/euro/matchdetails.php?matchid={match_id}"
    _ODDS_URL_TEMPLATE = "http://www.betexplorer.com/gres/ajax-matchodds.php?t=d&e={match_id}"

    def __init__(self, data):
        data = data.replace(r'&nbsp;', " ")
        self.tree = etree.HTML(data)
        super().__init__(data)

    @classmethod
    def get_url_from_id(cls, match_id):
        return cls.URL_TEMPLATE.format(match_id=match_id)
    
    @property
    def match_id(self):
        script_node = self.tree.xpath('//*[@id="content"]/script')[0]
        m = re.search(r"matchdetails_init\('(?P<match_id>.+?)'", script_node.text)
        return m.group("match_id")


    @property
    def info(self):
        # Date of the match
        date = datetime.strptime(self.tree.xpath('//*[@id="md-date"]')[0].text, "%d.%m.%Y").date()

        # The teams
        team1 = self.tree.xpath('//table[@class="tscore"]/tr/th[1]/strong')[0].text
        team2 = self.tree.xpath('//table[@class="tscore"]/tr/th[2]/strong')[0].text

        match_info = {
            'date': date,
            'team1': team1,
            'team2': team2
        }

        return match_info

    @property
    def odds_ids(self):
        # We retrieve the part of the page that contains the odds (doesn't exist, generated by JavaScript)
        # TODO: should be avoided maybe ?
        odds_html = requests.get(self._ODDS_URL_TEMPLATE.format(match_id=self.match_id)).text
        tree = etree.HTML(odds_html)
        odds_types = tree.xpath('//ul[contains(@class, "localmenu")]')[0]

        # Yield all the available odds types
        for odds_type in odds_types:
            onclick = odds_type[0].get("onclick")
            if onclick is not None:  # It is None if there is no odds of the given type
                m = re.match(r"match_change_bettype\('d', '.+?', '(?P<id>.+?)'\); return false;",
                             onclick)
                yield m.group("id")


class OddsPage(BasePage):

    URL_TEMPLATE = "http://www.betexplorer.com/gres/ajax-matchodds.php?t=d&e={match_id}&b={odds_id}"

    def __init__(self, data):
        data = data.replace(r'&nbsp;', " ")
        self.tree = etree.HTML(data)
        super().__init__(data)

    @classmethod
    def get_url_from_ids(cls, match_id, odds_id):
        return cls.URL_TEMPLATE.format(match_id=match_id, odds_id=odds_id)

    @staticmethod
    def _value_from_cell(cell):
        data_odd = cell.get("data-odd")
        if data_odd is not None:
            return float_or_none(cell.get("data-odd"))
        else:
            try:
                return float(cell.text)
            except ValueError:
                return cell.text

    @property
    def odds_id(self):
        onclick = self.tree.xpath('//ul[@class="localmenu nomb"]/li[@class="set"]/a')[0].get("onclick")
        m = re.match(r"match_change_bettype\('d', '.+?', '(?P<id>.+?)'\); return false;",
                     onclick)
        return m.group("id")

    @property
    def type(self):
        t = self.tree.xpath('//ul[@class="localmenu nomb"]/li[@class="set"]/a')[0].text
        # Remove trailing space
        if t[-1] == " ":
            t = t[:-1]
        return t

    @property
    def odds(self):
        bookmakers = self.tree.xpath('//div[@id="odds-content"]/table/tbody')[0]
        for bookmaker in bookmakers:
            odd = {
                "company_name": bookmaker[0][0][0].tail,
                "odds": [self._value_from_cell(cell) for cell in bookmaker[1:]],
                "type": self.type,
                "odds_id": self.odds_id
            }
            yield odd


class OddsScraper:

    def __init__(self, competition_page):
        self.competition_page = competition_page

    def scrape(self, types=None):
        """
        Scrape the odds for a given competition page.
        Optionally, specify which type of odds to scrape ('1x2', 'ha', 'ah', 'dc', 'ou', 'bts').

        :return: Yield dict of odds
        """
        if types is None:
            types = ('1x2', 'ha', 'ah', 'dc', 'ou', 'bts')
        for match_id in self.competition_page.matches_ids:
            # Find the odds ids
            match_url = MatchPage.get_url_from_id(match_id)
            mp = MatchPage.from_url(match_url)
            for odds_id in mp.odds_ids:
                # Yield the odds
                odds_url = OddsPage.get_url_from_ids(match_id, odds_id)
                odds_page = OddsPage.from_url(odds_url)
                for odd in odds_page.odds():
                    if odd["id"] in types:
                        yield odd
