function dateUTCToParis(date) {
    return moment.tz(date, 'UTC').tz('Europe/Paris');
}

// TODO : classifier (later)
function KHistory(options = {}) {
    $.extend(this, KHistory.default_options, options);

    this.$container = $(this.container);

    this.$container.selectable({
        filter: 'div.group, div.entry',
        selected: function (e, ui) {
            $(ui.selected).each(function () {
                if ($(this).hasClass('group')) {
                    var id = $(this).data('id');
                    $(this).siblings('.entry').filter(function () {
                        return $(this).data('group_id') == id
                    }).addClass('ui-selected');
                }
            });
        },
    });

    this.reset = function () {
        this.$container.html('');
    };

    this.add_history_group = function (group) {
        var $day = this._get_or_create_day(group['at']);
        var $group = this._group_html(group);

        $day.after($group);

        var trigramme = group['on_acc_trigramme'];
        var is_cof = group['is_cof'];
        var type = group['type']
        // TODO : simplifier ça ?
        switch (type) {
            case 'operation':
                for (let ope of group['entries']) {
                    var $ope = this._ope_html(ope, is_cof, trigramme);
                    $ope.data('group_id', group['id']);
                    $group.after($ope);
                }
                break;
            case 'transfer':
                for (let transfer of group['entries']) {
                    var $transfer = this._transfer_html(transfer);
                    $transfer.data('group_id', group['id']);
                    $group.after($transfer);
                }
                break;
        }
    }

    this._ope_html = function (ope, is_cof, trigramme) {
        var $ope_html = $(this.template_ope);
        var parsed_amount = parseFloat(ope['amount']);
        var amount = amountDisplay(parsed_amount, is_cof, trigramme);
        var infos1 = '', infos2 = '';

        if (ope['type'] == 'purchase') {
            infos1 = ope['article_nb'];
            infos2 = ope['article__name'] ? ope['article__name'] : 'Article supprimé';
        } else {
            infos1 = parsed_amount.toFixed(2) + '€';
            switch (ope['type']) {
                case 'initial':
                    infos2 = 'Initial';
                    break;
                case 'withdraw':
                    infos2 = 'Retrait';
                    break;
                case 'deposit':
                    infos2 = 'Charge';
                    break;
                case 'edit':
                    infos2 = 'Édition';
                    break;
            }
        }

        $ope_html
            .data('type', 'operation')
            .data('id', ope['id'])
            .find('.amount').text(amount).end()
            .find('.infos1').text(infos1).end()
            .find('.infos2').text(infos2).end();

        var addcost_for = ope['addcost_for__trigramme'];
        if (addcost_for) {
            var addcost_amount = parseFloat(ope['addcost_amount']);
            $ope_html.find('.addcost').text('(' + amountDisplay(addcost_amount, is_cof) + ' UKF pour ' + addcost_for + ')');
        }

        if (ope['canceled_at'])
            this.cancel_entry(ope, $ope_html);

        return $ope_html;
    }

    this._transfer_html = function (transfer) {
        var $transfer_html = $(this.template_transfer);
        var parsed_amount = parseFloat(transfer['amount']);
        var amount = parsed_amount.toFixed(2) + '€';

        $transfer_html
            .data('type', 'transfer')
            .data('id', transfer['id'])
            .find('.amount').text(amount).end()
            .find('.infos1').text(transfer['from_acc']).end()
            .find('.infos2').text(transfer['to_acc']).end();

        if (transfer['canceled_at'])
            this.cancel_entry(transfer, $transfer_html);

        return $transfer_html;
    }


    this.cancel_entry = function (entry, $entry = null) {
        if (!$entry)
            $entry = this.find_entry(entry["id"], entry["type"]);

        var cancel = 'Annulé';
        var canceled_at = dateUTCToParis(entry['canceled_at']);
        if (entry['canceled_by__trigramme'])
            cancel += ' par ' + entry['canceled_by__trigramme'];
        cancel += ' le ' + canceled_at.format('DD/MM/YY à HH:mm:ss');

        $entry.addClass('canceled').find('.canceled').text(cancel);
    }

    this._group_html = function (group) {
        var type = group['type'];


        switch (type) {
            case 'operation':
                var $group_html = $(this.template_opegroup);
                var trigramme = group['on_acc__trigramme'];
                var amount = amountDisplay(
                    parseFloat(group['amount']), group['is_cof'], trigramme);
                break;
            case 'transfer':
                var $group_html = $(this.template_transfergroup);
                $group_html.find('.infos').text('Transferts').end()
                var trigramme = '';
                var amount = '';
                break;
        }


        var at = dateUTCToParis(group['at']).format('HH:mm:ss');
        var comment = group['comment'] || '';

        $group_html
            .data('type', type)
            .data('id', group['id'])
            .find('.time').text(at).end()
            .find('.amount').text(amount).end()
            .find('.comment').text(comment).end()
            .find('.trigramme').text(trigramme).end();

        if (!this.display_trigramme)
            $group_html.find('.trigramme').remove();
        $group_html.find('.info').remove();

        if (group['valid_by__trigramme'])
            $group_html.find('.valid_by').text('Par ' + group['valid_by__trigramme']);

        return $group_html;
    }

    this._get_or_create_day = function (date) {
        var at = dateUTCToParis(date);
        var at_ser = at.format('YYYY-MM-DD');
        var $day = this.$container.find('.day').filter(function () {
            return $(this).data('date') == at_ser
        });
        if ($day.length == 1)
            return $day;
        var $day = $(this.template_day).prependTo(this.$container);
        return $day.data('date', at_ser).text(at.format('D MMMM YYYY'));
    }

    this.find_group = function (id, type = "operation") {
        return this.$container.find('.group').filter(function () {
            return ($(this).data('id') == id && $(this).data("type") == type)
        });
    }

    this.find_entry = function (id, type = 'operation') {
        return this.$container.find('.entry').filter(function () {
            return ($(this).data('id') == id && $(this).data('type') == type)
        });
    }

    this.update_opegroup = function (group, type = "operation") {
        var $group = this.find_group(group['id'], type);
        var trigramme = $group.find('.trigramme').text();
        var amount = amountDisplay(
            parseFloat(group['amount']), group['is_cof'], trigramme);
        $group.find('.amount').text(amount);
    }

    this.fetch = function (fetch_options = {}) {
        if (typeof (fetch_options) == "string")
            data = fetch_options
        else
            data = $.extend({}, this.fetch_options, fetch_options);

        return $.ajax({
            context: this,
            dataType: "json",
            url: django_urls["kfet.history.json"](),
            method: "GET",
            data: data,
        }).done(function (data) {
            for (let group of data['groups']) {
                this.add_history_group(group);
            }
        });
    }

    this._cancel = function (type, opes, password = "") {
        if (window.lock == 1)
            return false
        window.lock = 1;
        var that = this;
        return $.ajax({
            dataType: "json",
            url: django_urls[`kfet.${type}s.cancel`](),
            method: "POST",
            data: opes,
            beforeSend: function ($xhr) {
                $xhr.setRequestHeader("X-CSRFToken", csrftoken);
                if (password != '')
                    $xhr.setRequestHeader("KFetPassword", password);
            },

        }).done(function (data) {
            window.lock = 0;
            that.$container.find('.ui-selected').removeClass('ui-selected');
            for (let entry of data["canceled"]) {
                entry["type"] = type;
                that.cancel_entry(entry);
            }
            if (type == "operation") {
                for (let opegroup of data["opegroups_to_update"]) {
                    that.update_opegroup(opegroup)
                }
            }
        }).fail(function ($xhr) {
            var data = $xhr.responseJSON;
            switch ($xhr.status) {
                case 403:
                    requestAuth(data, function (password) {
                        that._cancel(type, opes, password);
                    });
                    break;
                case 400:
                    displayErrors(data);
                    break;
            }
            window.lock = 0;
        });
    }

    this.cancel_selected = function () {
        var opes_to_cancel = {
            "transfers": [],
            "operations": [],
        }
        this.$container.find('.entry.ui-selected').each(function () {
            type = $(this).data("type");
            opes_to_cancel[`${type}s`].push($(this).data("id"));
        });
        if (opes_to_cancel["transfers"].length > 0 && opes_to_cancel["operations"].length > 0) {
            // Lancer 2 requêtes AJAX et gérer tous les cas d'erreurs possibles est trop complexe
            $.alert({
                title: 'Erreur',
                content: "Impossible de supprimer des transferts et des opérations en même temps !",
                backgroundDismiss: true,
                animation: 'top',
                closeAnimation: 'bottom',
                keyboardEnabled: true,
            });
        } else if (opes_to_cancel["transfers"].length > 0) {
            delete opes_to_cancel["operations"];
            this._cancel("transfer", opes_to_cancel);
        } else if (opes_to_cancel["operations"].length > 0) {
            delete opes_to_cancel["transfers"];
            this._cancel("operation", opes_to_cancel);
        }
    }
}

KHistory.default_options = {
    container: '#history',
    template_day: '<div class="day"></div>',
    template_opegroup: '<div class="group"><span class="time"></span><span class="trigramme"></span><span class="amount"></span><span class="valid_by"></span><span class="comment"></span></div>',
    template_transfergroup: '<div class="group"><span class="time"></span><span class="infos"></span><span class="valid_by"></span><span class="comment"></span></div>',
    template_ope: '<div class="entry"><span class="amount"></span><span class="infos1"></span><span class="infos2"></span><span class="addcost"></span><span class="canceled"></span></div>',
    template_transfer: '<div class="entry"><span class="amount"></span><span class="infos1"></span><span class="glyphicon glyphicon-arrow-right"></span><span class="infos2"></span><span class="canceled"></span></div>',
    display_trigramme: true,
}
