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

# Copyright(C) 2016      Edouard Lambert
#
# This file is part of a weboob module.
#
# This weboob module is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This weboob 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 Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this weboob module. If not, see <http://www.gnu.org/licenses/>.


from weboob.browser.pages import HTMLPage, LoggedPage
from weboob.browser.elements import ListElement, ItemElement, method
from weboob.browser.filters.standard import CleanText, Capitalize, Format, Date, Regexp, CleanDecimal, Env, Field, Async, AsyncLoad
from weboob.browser.filters.html import Attr, Link
from weboob.capabilities.bank import Account, Investment, Transaction
from weboob.capabilities.base import NotAvailable
from weboob.exceptions import ActionNeeded, BrowserUnavailable


def MyDecimal(*args, **kwargs):
    kwargs.update(replace_dots=True, default=NotAvailable)
    return CleanDecimal(*args, **kwargs)


class BasePage(HTMLPage):
    def on_load(self):
        super(BasePage, self).on_load()

        if 'Erreur' in CleanText('//div[@id="main"]/h1', default='')(self.doc):
            err = CleanText('//div[@id="main"]/div[@class="content"]', default=u'Site indisponible')(self.doc)
            raise BrowserUnavailable(err)


class LoginPage(BasePage, HTMLPage):

    def get_values(self):
        values = {}
        virtual_keyboard = self.doc.xpath('//input[@keypad]')
        for input in virtual_keyboard:
            value = Attr(None, 'value').filter(input.xpath('.'))
            index = Attr(None, 'data-index').filter(input.xpath('.'))
            values[value] = index
        return values

    def get_password(self, password):
        values = self.get_values()
        if values:
            password = [values[c] for c in password]
        return "".join(password)

    def login(self, login, password):
        form = self.get_form(id="loginForm")
        form['username'] = login
        form['password'] = self.get_password(password)
        form.submit()


class AccountsPage(LoggedPage, BasePage, HTMLPage):
    @method
    class iter_accounts(ListElement):
        item_xpath = '//div[@id]/div[has-class("productDetails")]'

        class item(ItemElement):
            klass = Account

            load_details = Field('_link') & AsyncLoad

            obj_id = CleanText('.//dt[contains(text(), "contrat")]/following-sibling::dd[1]')
            obj_label = CleanText('.//div[has-class("title")]')
            obj_type = Account.TYPE_LIFE_INSURANCE
            obj_balance = Async('details') & MyDecimal('//strong[contains(text(), "Valeur") '
                'or contains(text(), "Epargne retraite")]/following-sibling::span')
            obj_valuation_diff = Async('details') & MyDecimal('.//a[contains(@title, "diff")]/parent::p')
            obj__link = Link(u'.//a[contains(text(), "Détail")]')
            # Additional waranty : need to know what to do with this
            obj__additionalwaranty = Env('additionalwaranty')

            def condition(self):
                return 'epargne' in Link(u'.//a[contains(text(), "Détail")]')(self)

            def parse(self, el):
                # Additional waranty
                doc = self.page.browser.open(Field('_link')(self)).page.doc
                additionalwaranty = []
                for line in doc.xpath(u'//h2[contains(text(), "complémentaire")]/following-sibling::div//div[@class="line"]'):
                    values = {}
                    values['label'] = CleanText().filter(line.xpath('./div[@data-label="Nom du support"]'))
                    values['amount'] = CleanText().filter(line.xpath('./div[@data-label="Montant total investi"]'))
                    additionalwaranty.append(values)
                self.env['additionalwaranty'] = additionalwaranty


class InvestmentPage(LoggedPage, HTMLPage):
    def get_history_link(self):
        link = self.doc.xpath(u'//a[contains(text(), "historique")]/@href')
        if link:
            return link[0]

    @method
    class iter_investment(ListElement):
        item_xpath = '//h2[has-class("feature")]/following-sibling::div/div[@class="line"]'

        class item(ItemElement):
            klass = Investment

            def load_details(self):
                # create URL with ISIN code if exists
                code = Field('code')(self)
                if code:
                    url = 'https://aviva.sixtelekurs.fr/opcvm.hts?isin=%s&environnement=internet' % code
                    return self.page.browser.async_open(url=url)

            obj_code = Regexp(Attr('./div[@data-label="Nom du support"]/a', 'onclick', default=''), '\"([^\"]+)', default=NotAvailable)
            obj_quantity = MyDecimal('./div[@data-label="Nombre de parts"]', default=NotAvailable)
            obj_unitvalue = MyDecimal('./div[@data-label="Valeur de la part"]')
            obj_valuation = MyDecimal('./div[@data-label="Valeur"]', default=NotAvailable)
            obj_vdate = Date(CleanText('./div[@data-label="Date de valeur"]'), dayfirst=True, default=NotAvailable)
            obj_unitprice = Async('details') & CleanDecimal('//td[@class="donnees"]/span[@id="VL_achat"]', default=NotAvailable)
            obj_diff_percent = Async('details') & CleanDecimal('//td[@class="donnees"]/span[@id="Performance"]', default=NotAvailable)
            obj_description = Async('details') & CleanText('//td[@class="donnees"]/span[@id="Nature"]', default=NotAvailable)

            def obj_label(self):
                # label xpath changes if there is a link to details
                label = CleanText('./div[@data-label="Nom du support"]', children=False)(self)
                if label:
                    return label
                return CleanText('./div[@data-label="Nom du support"]/a', children=False)(self)


class InvestmentElement(ItemElement):
    klass = Investment

    obj_label = CleanText('./div[@data-label="Nom du support" or @data-label="Support cible"]/span[1]')
    obj_quantity = MyDecimal('./div[contains(@data-label, "Nombre")]')
    obj_unitvalue = MyDecimal('./div[contains(@data-label, "Valeur")]')
    obj_valuation = MyDecimal('./div[contains(@data-label, "Montant")]')
    obj_vdate = Env('date')
    #obj_vdate = Field('date')


class TransactionElement(ItemElement):
    klass = Transaction

    obj_label = Format('%s du %s', Field('_labeltype'), Field('date'))
    obj_date = Date(Regexp(CleanText('./ancestor::div[@class="onerow" or starts-with(@id, "term") or has-class("grid")]/'
                                     'preceding-sibling::h3[1]//div[contains(text(), "Date")]'),
                           r'(\d{2}\/\d{2}\/\d{4})'),
                    dayfirst=True)
    obj_type = Transaction.TYPE_BANK

    obj_amount = MyDecimal('./ancestor::div[@class="onerow" or starts-with(@id, "term") or has-class("grid")]/'
                           'preceding-sibling::h3[1]//div[has-class("montant-mobile")]', default=NotAvailable)

    obj__labeltype = Regexp(Capitalize('./preceding::h2[@class="feature"][1]'),
                                      'Historique Des\s+(\w+)')

    def obj_investments(self):
        return list(self.iter_investments(self.page, parent=self))

    @method
    class iter_investments(ListElement):
        item_xpath = './div[@class="line"]'

        class item(InvestmentElement):
            pass

    def parse(self, el):
        self.env['date'] = Field('date')(self)


class HistoryPage(LoggedPage, HTMLPage):
    @method
    class iter_history(ListElement):
        class iter_simple(ListElement):
            def find_elements(self):
                # "arbitrage" transactions are split in 2 table-responsive
                # the html tree is a mess
                for sub in self.el.xpath('//div[not(@id="divAvance")]/div[@class="table-responsive"]'):
                    if (sub.getparent().attrib.get('class') != 'onerow' or
                        'grid' not in sub.getparent().getparent().attrib.get('class')):

                        yield sub

            obj_date = Date(Regexp(CleanText('./ancestor::div[starts-with(@id, "term")]/'
                                            'preceding-sibling::h3[1]//div[contains(text(), "Date")]'),
                                r'\d{2}\/\d{2}\/\d{4}'),
                            dayfirst=True)

            class item(TransactionElement):
                class iter_investments(ListElement):
                    item_xpath = './div[@class="line"]'

                    class item(InvestmentElement):
                        pass

        class iter_complex(ListElement):
            item_xpath = '//div[has-class("grid")]/div[@class="onerow"]'

            class item(TransactionElement):
                class iter_investments(ListElement):
                    item_xpath = './div[@class="table-responsive"]/div[@class="line"]'

                    class item(InvestmentElement):
                        pass

        class iter_avance(ListElement):
            item_xpath = '//div[@id="divAvance"]/div[@class="table-responsive"]/div[@class="line"]'

            class item(ItemElement):
                klass = Transaction

                obj_label = Format('%s du %s', Field('_labeltype'), Field('date'))
                obj_type = Transaction.TYPE_BANK
                obj_date = Date(CleanText(u'./div[@data-label="Date d\'effet"]', children=False), dayfirst=True)
                obj_amount = CleanDecimal(u'./div[@data-label="Montant en €"]', replace_dots=True)
                obj__labeltype = Regexp(Capitalize('./preceding::h2[@class="feature"][1]'),
                                        'Historique Des\s+(\w+)')


class ActionNeededPage(LoggedPage, HTMLPage):
    def on_load(self):
        raise ActionNeeded(u'Veuillez mettre à jour vos coordonnées')


class InvestDetail(LoggedPage, HTMLPage):
    pass
