# -*- coding: utf-8 -*-

# Copyright(C) 2017      Vincent A
#
# This file is part of a woob module.
#
# This woob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This woob module is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this woob module. If not, see <http://www.gnu.org/licenses/>.

import re
from datetime import datetime

from woob.browser.elements import method, ListElement, ItemElement
from woob.browser.filters.html import AbsoluteLink
from woob.browser.filters.standard import CleanText, Env, Field, Format
from woob.browser.pages import HTMLPage, pagination
from woob.capabilities.base import StringField
from woob.capabilities.calendar import BaseCalendarEvent, CATEGORIES


LABEL_TO_CAT = {
    'Cinéma': CATEGORIES.CINE,
    'Concerts': CATEGORIES.CONCERT,
    'Conférence': CATEGORIES.CONF,
    'Expos ': CATEGORIES.EXPO,
    'Spectacles': CATEGORIES.SPECTACLE,
    'Sport': CATEGORIES.SPORT,
    'Théâtre': CATEGORIES.THEATRE,
}


CAT_TO_LABEL = {v: k for k, v in LABEL_TO_CAT.items()}


FRENCH_DAYS = ['lundi' ,'mardi', 'mercredi', 'jeudi', 'vendredi', 'samedi', 'dimanche']


class BREvent(BaseCalendarEvent):
    siteid = StringField('Site id')


class SearchPage(HTMLPage):
    def search(self, q):
        form = self.get_form(name='form1')
        form['titre'] = q.summary or ''
        form['cp'] = q.city or ''
        form['tri'] = 'date'
        form['jj'] = q.start_date.strftime('%d')
        form['dt'] = q.start_date.strftime('%Y-%m')

        form['idrub'] = []
        for cat in q.categories:
            if cat not in CAT_TO_LABEL:
                continue
            for id in self.doc.xpath('//label[@class="lrubr1"][contains(text(),$txt)]/input/@value', txt=CAT_TO_LABEL[cat]):
                form['idrub'].append(id)
                break
        assert form['idrub']

        form.submit()


class TimeParser(object):
    # phrasing can be: "du lundi au samedi à 16h et le lundi et le dimanche à 15h30, dimanche, mardi à 12h, 13h et 14h"
    def __init__(self, txt, weekday):
        self.weekday = weekday

        txt = re.sub(r'\ble\s+|\s+et\s+|,', ' ', txt)
        txt = re.sub(r'\s\s+', ' ', txt).strip()

        self.parts = txt.split()
        self.res = []
        self.days = []

    def do_parse(self):
        for i in self.parts:
            self.parse(i)

    def parse_start(self, i):
        if i == 'du':
            self.parse = self.parse_range
        else:
            self.days.append(FRENCH_DAYS.index(i))
            self.parse = self.parse_after_day

    def parse_range(self, i):
        self.rstart = FRENCH_DAYS.index(i)
        self.parse = self.parse_to

    def parse_to(self, i):
        assert i == 'au'
        self.parse = self.parse_to2

    def parse_to2(self, i):
        self.rend = FRENCH_DAYS.index(i)
        self.days.extend(range(self.rstart, self.rend + 1))
        self.parse = self.parse_after_day

    def parse_after_day(self, i):
        if i == 'à':
            self.parse = self.parse_time
        else:
            self.parse_start(i)

    time_re = re.compile(r'(\d+)h(\d*)$')

    def parse_time(self, i):
        m = self.time_re.match(i)
        if self.weekday in self.days:
            self.res.append((int(m.group(1)), int(m.group(2) or 0)))

        self.parse = self.parse_after_time

    def parse_after_time(self, i):
        if self.time_re.match(i):
            self.parse_time(i)
        else:
            self.days = []
            self.parse = self.parse_start
            self.parse(i)

    parse = parse_start


class ResultsPage(HTMLPage):
    @pagination
    @method
    class iter_events(ListElement):
        item_xpath = '//table[@id="preliste"]/tr'
        next_page = AbsoluteLink('(//a[img[contains(@src,"btnPageSuivanteSmall")]])[1]')

        class item(ItemElement):
            klass = BREvent

            obj_summary = CleanText('.//h4')
            obj_url = AbsoluteLink('.//h4/a')
            obj_description = CleanText('.//div[@class="libellepreliste"]')
            obj_city = CleanText('(.//span[@class="lieu"]/a)[2]')
            obj_location = CleanText('(.//span[@class="lieu"]/a)[1]')
            obj_timezone = 'Europe/Paris'

            def obj_price(self):
                return float(CleanText('.//span[@class="prixli"]')(self).replace('€', '.'))

            def obj__date_hours(self):
                date = Env('date')(self)
                weekday = date.weekday()

                txt = CleanText('.//p[@class="sb"]')(self).lower()
                m = re.match(r'du \d+/\d+/\d+ au \d+/\d+/\d+ (.*)', txt)
                if m:
                    txt = m.group(1)
                    p = TimeParser(txt, weekday)
                    p.do_parse()
                    return p.res

                m = re.match('le \w+ \d+ \w+ \d+ à (\d+)h(\d*)$', txt, re.UNICODE)
                return [(int(m.group(1)), int(m.group(2) or 0))]

            obj_start_date = Env('date')

            def obj_category(self):
                text = CleanText('.//h4/following-sibling::span[@class="small"]/a')(self)
                for k in LABEL_TO_CAT:
                    if k in text:
                        return LABEL_TO_CAT[k]
                return CATEGORIES.AUTRE

            def obj_siteid(self):
                return self.page.browser.event.match(Field('url')(self)).group('id')


class EventPage(HTMLPage):
    @method
    class get_event(ItemElement):
        klass = BREvent

        def obj_url(self):
            return self.page.url

        obj_summary = CleanText('//div[@class="evtTitre"]/h2')
        obj_description = Format('%s\n%s', CleanText('//h6[@itemprop]'), CleanText('//div[@id="speDescription"]'))

        obj_location = CleanText('//td[@class="colLeftSeparator"]//a[starts-with(@href,"/lieu/")]')
        obj_city = CleanText('//td[@class="colLeftSeparator"]//a[starts-with(@href,"/spectacle-")]')
        obj_timezone = 'Europe/Paris'

        def obj_siteid(self):
            return self.page.browser.event.match(Field('url')(self)).group('id')

        def obj_category(self):
            text = CleanText('//div[@id="contextchemin"]')(self)
            for k in LABEL_TO_CAT:
                if k in text:
                    return LABEL_TO_CAT[k]
            return CATEGORIES.AUTRE


class EventDatesPage(HTMLPage):
    def fetch_by_date(self, event, ymd, hm):
        book = self.browser.book.build(id=event.siteid, ymd=ymd, hm=hm)
        book = book.replace(self.browser.BASEURL, '')
        for a in self.doc.xpath('//a[@href = $url]', url=book):
            event.price = self.parse_price(a)
            return

    def parse_price(self, a):
        return float(re.search(r'\d+€\d*', a.attrib['title']).group(0).replace('€', '.'))

    def get_first(self, event):
        prefix = '/evtBook.htm?idevt=%s' % event.siteid
        for a in self.doc.xpath('//a[starts-with(@href, $pfx)]', pfx=prefix):
            bookurl = self.browser.absurl(a.attrib['href'], base=True)
            d = self.browser.book.match(bookurl).groupdict()
            s = '%sT%s' % (d['ymd'], d['hm'])
            event.start_date = datetime.strptime(s, '%Y-%m-%dT%H:%M')
            event.price = self.parse_price(a)
            return
