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

# Copyright(C) 2017 Vincent Ardisson
#
# 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 __future__ import unicode_literals

from ast import literal_eval
from decimal import Decimal
import re

from weboob.browser.pages import LoggedPage, JsonPage, HTMLPage
from weboob.browser.elements import ItemElement, DictElement, method
from .compat.weboob_browser_filters_standard import Date, Eval, CleanText, Field, CleanDecimal
from weboob.browser.filters.json import Dict
from .compat.weboob_capabilities_bank import Account, Transaction
from weboob.capabilities.base import NotAvailable
from weboob.tools.json import json
from weboob.tools.compat import basestring
from weboob.exceptions import ActionNeeded, BrowserUnavailable


def float_to_decimal(f):
    return Decimal(str(f))

def parse_decimal(s):
    # we might get 1,399,680 in rupie indonésienne
    if s.count(',') > 1 and not s.count('.'):
        return CleanDecimal(replace_dots=(',', '.')).filter(s)
    # we don't know which decimal format this account will use
    comma = s.rfind(',') > s.rfind('.')
    return CleanDecimal(replace_dots=comma).filter(s)


class WrongLoginPage(HTMLPage):
    pass


class AccountSuspendedPage(HTMLPage):
    pass


class NoCardPage(HTMLPage):
    def on_load(self):
        raise ActionNeeded()


class NotFoundPage(HTMLPage):
    def on_load(self):
        alert_header = CleanText('//h1[@class="alert-header"]/span')(self.doc)
        alert_content = CleanText('//p[@class="alert-subtitle"]/span')(self.doc)
        raise BrowserUnavailable(alert_header, alert_content)


class LoginPage(HTMLPage):
    def login(self, username, password):
        form = self.get_form(name='ssoform')
        form['UserID'] = username
        form['USERID'] = username
        form['Password'] = password
        form['PWD'] = password
        form.submit()


class AccountsPage(LoggedPage, HTMLPage):
    def iter_accounts(self):
        for line in self.doc.xpath('//script[@id="initial-state"]')[0].text.split('\n'):
            m = re.search('window.__INITIAL_STATE__ = (.*);', line)
            if m:
                data = json.loads(literal_eval(m.group(1)))
                break
        else:
            assert False, "data was not found"

        assert data[13] == 'core'
        assert len(data[14]) == 3

        # search for products to get products list
        for index, el in enumerate(data[14][2]):
            if 'products' in el:
                accounts_data = data[14][2][index+1]

        assert len(accounts_data) == 2
        assert accounts_data[1][4] == 'productsList'

        accounts_data = accounts_data[1][5]
        token = []

        for account_data in accounts_data:
            if isinstance(account_data, basestring):
                balances_token = account_data

            elif isinstance(account_data, list) and not account_data[4][2][0]=="Canceled":
                acc = Account()
                if len(account_data) > 15:
                    token.append(account_data[-11])
                    acc._idforJSON =  account_data[10][-1]
                else:
                    acc._idforJSON = account_data[-5][-1]
                acc._idforJSON = re.sub('\s+', ' ', acc._idforJSON)
                acc.number = '-%s' % account_data[2][2]
                acc.label = '%s %s' % (account_data[6][4], account_data[10][-1])
                acc._balances_token = acc.id = balances_token
                acc._token = token[-1]
                acc.type = Account.TYPE_CARD
                yield acc


class JsonBalances(LoggedPage, JsonPage):
    def set_balances(self, accounts):
        by_token = {a._balances_token: a for a in accounts}
        for d in self.doc:
            # coming is what should be refunded at a futur deadline
            by_token[d['account_token']].coming = -float_to_decimal(d['total_debits_balance_amount'])
            # balance is what is currently due
            by_token[d['account_token']].balance = -float_to_decimal(d['remaining_statement_balance_amount'])


class JsonBalances2(LoggedPage, JsonPage):
    def set_balances(self, accounts):
        by_token = {a._balances_token: a for a in accounts}
        for d in self.doc:
            by_token[d['account_token']].balance = -float_to_decimal(d['total']['payments_credits_total_amount'])
            by_token[d['account_token']].coming = -float_to_decimal(d['total']['debits_total_amount'])
            # warning: payments_credits_total_amount is not the coming value here


class CurrencyPage(LoggedPage, JsonPage):
    def get_currency(self):
        return self.doc['currency']


class JsonPeriods(LoggedPage, JsonPage):
    def get_periods(self):
        return [p['statement_end_date'] for p in self.doc]


class JsonHistory(LoggedPage, JsonPage):
    def get_count(self):
        return self.doc['total_count']

    @method
    class iter_history(DictElement):
        item_xpath = 'transactions'

        class item(ItemElement):
            klass = Transaction

            def obj_type(self):
                if Field('raw')(self) in self.page.browser.SUMMARY_CARD_LABEL:
                    return Transaction.TYPE_CARD_SUMMARY
                elif Field('amount')(self) > 0:
                    return Transaction.TYPE_ORDER
                else:
                    return Transaction.TYPE_DEFERRED_CARD

            obj_raw = CleanText(Dict('description', default=''))
            obj_date = Date(Dict('statement_end_date', default=None), default=None)
            obj_rdate = Date(Dict('charge_date'))
            obj_vdate = obj_bdate = Date(Dict('post_date', default=None), default=NotAvailable)
            obj_amount = Eval(lambda x: -float_to_decimal(x), Dict('amount'))
            obj_original_currency = Dict('foreign_details/iso_alpha_currency_code', default=NotAvailable)
            obj_commission = CleanDecimal(Dict('foreign_details/commission_amount', default=NotAvailable), sign=lambda x: -1, default=NotAvailable)
            obj__owner = CleanText(Dict('embossed_name'))
            obj_id = Dict('reference_id', default=NotAvailable)

            def obj_original_amount(self):
                # amount in the account's currency
                amount = Field("amount")(self)
                # amount in the transaction's currency
                original_amount = Dict('foreign_details/amount', default=NotAvailable)(self)
                if Field("original_currency")(self) == "XAF":
                    original_amount = abs(CleanDecimal(replace_dots=('.')).filter(original_amount))
                elif not original_amount:
                    return NotAvailable
                else:
                    original_amount = abs(parse_decimal(original_amount))
                if amount < 0:
                    return -original_amount
                else:
                    return original_amount

            # obj__ref = Dict('reference_id')
            obj__ref = Dict('identifier')

