import ngModule from '../module';
import './style.scss';

class Controller {
    constructor($scope, $state, $http, vnApp, $translate) {
        this.$scope = $scope;
        this.vnApp = vnApp;
        this.$translate = $translate;
        this.$state = $state;
        this.$stateParams = $state.params;
        this.$http = $http;
        this.edit = {};
        this.moreOptions = [
            {
                name: 'Send shortage SMS',
                callback: this.showSMSDialog
            }, {
                name: 'Mark as reserved',
                callback: this.markAsReserved,
                show: () => this.isEditable
            }, {
                name: 'Unmark as reserved',
                callback: this.unmarkAsReserved,
                show: () => this.isEditable
            }, {
                name: 'Update discount',
                callback: this.showEditDialog,
                show: () => this.isEditable
            }, {
                name: 'Add claim',
                callback: this.createClaim
            }, {
                name: 'Recalculate price',
                callback: this.calculateSalePrice,
                show: () => this.hasOneSaleSelected()
            },
        ];
        this._sales = [];
        this.imagesPath = '//verdnatura.es/vn-image-data/catalog';
    }

    get ticket() {
        return this._ticket;
    }

    set ticket(value) {
        this._ticket = value;
        this.isTicketEditable();
        this.isTicketLocked();
    }

    get sales() {
        return this._sales;
    }

    set sales(value) {
        this._sales = value;
        this.refreshTotal();
    }

    get editedPrice() {
        return this._editedPrice;
    }

    set editedPrice(value) {
        this._editedPrice = value;
        this.updateNewPrice();
    }

    refreshTotal() {
        this.loadSubTotal();
        this.loadVAT();
    }

    loadSubTotal() {
        if (!this.$stateParams.id || !this.sales) return;
        this.$http.get(`Tickets/${this.$stateParams.id}/subtotal`).then(res => {
            this.subtotal = res.data || 0.0;
        });
    }

    getSaleTotal(sale) {
        if (!sale.quantity || !sale.price)
            return;

        return sale.quantity * sale.price * ((100 - sale.discount) / 100);
    }

    loadVAT() {
        this.VAT = 0.0;
        if (!this.$stateParams.id || !this.sales) return;
        this.$http.get(`Tickets/${this.$stateParams.id}/getVAT`).then(res => {
            this.VAT = res.data || 0.0;
        });
    }

    get total() {
        return this.subtotal + this.VAT;
    }

    onMoreOpen() {
        let options = this.moreOptions.filter(option => {
            const hasShowProperty = Object.hasOwnProperty.call(option, 'show');
            const shouldShow = !hasShowProperty || option.show === true ||
                typeof option.show === 'function' && option.show();

            return (shouldShow && (option.always || this.isChecked));
        });
        this.$scope.moreButton.data = options;
    }

    onMoreChange(callback) {
        callback.call(this);
    }

    get isChecked() {
        if (this.sales) {
            for (let instance of this.sales)
                if (instance.checked) return true;
        }

        return false;
    }

    /**
     * Returns checked instances
     *
     * @return {Array} Checked instances
     */
    checkedLines() {
        if (!this.sales) return;

        return this.sales.filter(sale => {
            return sale.checked;
        });
    }

    /**
     * Returns new instances
     *
     * @return {Array} New instances
     */
    newInstances() {
        if (!this.sales) return;

        return this.sales.filter(sale => {
            return !sale.id;
        });
    }

    /**
     * Returns an array of indexes
     * from checked instances
     *
     * @return {Array} Indexes of checked instances
     */
    checkedLinesIndex() {
        if (!this.sales) return;

        let indexes = [];
        this.sales.forEach((sale, index) => {
            if (sale.checked) indexes.push(index);
        });

        return indexes;
    }

    firstCheckedLine() {
        const checkedLines = this.checkedLines();
        if (checkedLines)
            return checkedLines[0];
    }

    /**
     * Returns the total of checked instances
     *
     * @return {Number} Total checked instances
     */
    totalCheckedLines() {
        const checkedLines = this.checkedLines();
        if (checkedLines)
            return checkedLines.length;
    }

    removeCheckedLines() {
        const sales = this.checkedLines();

        sales.forEach(sale => {
            const index = this.sales.indexOf(sale);
            this.sales.splice(index, 1);
        });

        if (this.newInstances().length === 0)
            this.$scope.watcher.updateOriginalData();

        this.refreshTotal();
    }

    onStateOkClick() {
        let filter = {where: {code: 'OK'}, fields: ['id']};
        let json = encodeURIComponent(JSON.stringify(filter));
        return this.$http.get(`States?filter=${json}`).then(res => {
            this.onStateChange(res.data[0].id);
        });
    }

    onStateChange(value) {
        let params = {ticketFk: this.$state.params.id, stateFk: value};
        this.$http.post('TicketTrackings/changeState', params).then(() => {
            this.card.reload();
            this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
        }).finally(() => {
            if (this.newInstances().length === 0)
                this.$scope.watcher.updateOriginalData();
        });
    }

    onRemoveLinesClick(response) {
        if (response === 'accept') {
            let sales = this.checkedLines();

            // Remove unsaved instances
            sales.forEach((sale, index) => {
                if (!sale.id) sales.splice(index);
            });

            let params = {sales: sales, actualTicketFk: this.ticket.id};
            let query = `Sales/removes`;
            this.$http.post(query, params).then(() => {
                this.removeCheckedLines();
                this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
            });
        }
    }

    showRemoveLinesDialog() {
        this.$scope.deleteLines.show();
    }

    showTransferPopover(event) {
        this.setTransferParams();
        this.$scope.transfer.parent = event.target;
        this.$scope.transfer.show();
    }

    setTransferParams() {
        const checkedSales = JSON.stringify(this.checkedLines());
        const sales = JSON.parse(checkedSales);
        this.transfer = {
            lastActiveTickets: [],
            sales: sales
        };

        const params = {ticketId: this.ticket.id};
        const query = `clients/${this.ticket.clientFk}/lastActiveTickets`;
        this.$http.get(query, {params}).then(res => {
            this.transfer.lastActiveTickets = res.data;
        });
    }

    transferSales(ticketId) {
        const params = {
            ticketId: ticketId,
            sales: this.transfer.sales
        };

        this.$scope.watcher.updateOriginalData();

        const query = `tickets/${this.ticket.id}/transferSales`;
        this.$http.post(query, params).then(res => {
            this.goToTicket(res.data.id);
        });
    }

    createClaim() {
        const claim = {
            ticketFk: this.ticket.id,
            clientFk: this.ticket.clientFk,
            ticketCreated: this.ticket.shipped
        };
        const sales = this.checkedLines();

        if (this.newInstances().length === 0)
            this.$scope.watcher.updateOriginalData();

        this.$http.post(`Claims/createFromSales`, {claim: claim, sales: sales}).then(res => {
            this.$state.go('claim.card.basicData', {id: res.data.id});
        });
    }

    goToTicket(ticketId) {
        this.$state.go('ticket.card.sale', {id: ticketId});
    }

    // Slesperson Mana
    getManaSalespersonMana() {
        this.$http.get(`Tickets/${this.$state.params.id}/getSalesPersonMana`).then(res => {
            this.mana = res.data;
        });
    }

    // Item Descriptor
    showDescriptor(event, itemFk) {
        this.quicklinks = {
            btnThree: {
                icon: 'icon-transaction',
                state: `item.card.diary({
                    id: ${itemFk}, 
                    warehouseFk: ${this.ticket.warehouseFk},
                    ticketFk: ${this.ticket.id}
                })`,
                tooltip: 'Item diary'
            }
        };
        this.$scope.descriptor.itemFk = itemFk;
        this.$scope.descriptor.parent = event.target;
        this.$scope.descriptor.show();
    }

    onDescriptorLoad() {
        this.$scope.popover.relocate();
    }

    showEditPricePopover(event, sale) {
        if (!this.isEditable) return;
        this.sale = sale;
        this.editedPrice = this.sale.price;
        this.edit = {
            ticketFk: this.ticket.id,
            id: sale.id,
            quantity: sale.quantity
        };
        this.$scope.editPricePopover.parent = event.target;
        this.$scope.editPricePopover.show();
    }

    updatePrice() {
        if (this.editedPrice != this.sale.price) {
            this.$http.post(`Sales/${this.edit.id}/updatePrice`, {newPrice: this.editedPrice}).then(res => {
                this.sale.price = res.data.price;

                this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
            }).finally(() => {
                if (this.newInstances().length === 0)
                    this.$scope.watcher.updateOriginalData();
            });
        }

        this.$scope.editPricePopover.hide();
    }

    updateNewPrice() {
        this.newPrice = this.sale.quantity * this.editedPrice - ((this.sale.discount * (this.sale.quantity * this.editedPrice)) / 100);
    }

    showEditDiscountPopover(event, sale) {
        if (this.isLocked) return;

        this.sale = sale;
        this.edit = [{
            ticketFk: this.ticket.id,
            id: sale.id,
            quantity: sale.quantity,
            price: sale.price,
            discount: sale.discount
        }];
        this.$scope.editPopover.parent = event.target;
        this.$scope.editPopover.show();
    }

    showEditDialog() {
        this.edit = this.checkedLines();
        this.$scope.editDialog.show();
    }

    hideEditDialog() {
        this.$scope.model.refresh();
        this.$scope.editDialog.hide();
    }

    hideEditPopover() {
        this.$scope.model.refresh();
        this.$scope.editPopover.hide();
    }

    /*
     * Unmark sale as reserved
     */
    unmarkAsReserved() {
        this.setReserved(false);
    }

    /*
     * Mark sale as reserved
     */
    markAsReserved() {
        this.setReserved(true);
    }

    setReserved(reserved) {
        let selectedSales = this.checkedLines();
        let params = {sales: selectedSales, ticketFk: this.ticket.id, reserved: reserved};

        let reservedSales = new Map();
        this.$http.post(`Sales/reserve`, params).then(res => {
            let isReserved = res.config.data.reserved;

            res.config.data.sales.forEach(sale => {
                reservedSales.set(sale.id, {reserved: isReserved});
            });

            this.sales.forEach(sale => {
                const reservedSale = reservedSales.get(sale.id);
                if (reservedSale)
                    sale.reserved = reservedSale.reserved;
            });
        }).finally(() => {
            if (this.newInstances().length === 0)
                this.$scope.watcher.updateOriginalData();
        });
    }

    newOrderFromTicket() {
        this.$http.post(`Orders/newFromTicket`, {ticketFk: this.ticket.id}).then(res => {
            const path = this.$state.href('order.card.catalog', {id: res.data});
            window.open(path, '_blank');

            this.vnApp.showSuccess(this.$translate.instant('Order created'));
        });
    }

    showSMSDialog() {
        const address = this.ticket.address;
        const client = this.ticket.client;
        const phone = address.mobile || address.phone ||
            client.mobile || client.phone;
        const sales = this.checkedLines();
        const items = sales.map(sale => {
            return `${sale.quantity} ${sale.concept}`;
        });
        const notAvailables = items.join(', ');
        const params = {
            ticketFk: this.ticket.id,
            created: this.ticket.created,
            notAvailables
        };
        this.newSMS = {
            destinationFk: this.ticket.clientFk,
            destination: phone,
            message: this.$translate.instant('Product not available', params)
        };
        this.$scope.sms.open();
    }

    /**
     * Inserts a new instance
     */
    add() {
        this.$scope.model.insert({});
    }

    /*
     * Creates a new sale if it's a new instance
     * Updates the sale quantity for existing instance
     */
    onChangeQuantity(sale) {
        if (!sale.quantity) return;

        if (!sale.id)
            return this.addSale(sale);

        this.updateQuantity(sale);
    }

    /*
     * Updates a sale quantity
     */
    updateQuantity(sale) {
        const data = {quantity: parseInt(sale.quantity)};
        const query = `Sales/${sale.id}/updateQuantity`;
        this.$http.post(query, data).then(() => {
            this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
        }).catch(e => {
            this.$scope.model.refresh();
            throw e;
        }).finally(() => {
            if (this.newInstances().length === 0)
                this.$scope.watcher.updateOriginalData();
        });
    }

    /*
     * Updates a sale concept
     */
    updateConcept(sale) {
        const data = {newConcept: sale.concept};
        const query = `Sales/${sale.id}/updateConcept`;
        this.$http.post(query, data).then(() => {
            this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
        }).catch(e => {
            this.$scope.model.refresh();
            throw e;
        }).finally(() => {
            if (this.newInstances().length === 0)
                this.$scope.watcher.updateOriginalData();
        });
    }

    /*
     * Adds a new sale
     */
    addSale(sale) {
        const data = {
            itemId: sale.itemFk,
            quantity: sale.quantity
        };
        const query = `tickets/${this.ticket.id}/addSale`;
        this.$http.post(query, data).then(res => {
            if (!res.data) return;

            const newSale = res.data;

            sale.id = newSale.id;
            sale.image = newSale.item.image;
            sale.subName = newSale.item.subName;
            sale.concept = newSale.concept;
            sale.quantity = newSale.quantity;
            sale.discount = newSale.discount;
            sale.price = newSale.price;
            sale.item = newSale.item;

            this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
        }).finally(() => {
            if (this.newInstances().length === 0)
                this.$scope.watcher.updateOriginalData();
        });
    }

    isTicketEditable() {
        this.$http.get(`Tickets/${this.$state.params.id}/isEditable`).then(res => {
            this.isEditable = res.data;
        });
    }

    isTicketLocked() {
        this.$http.get(`Tickets/${this.$state.params.id}/isLocked`).then(res => {
            this.isLocked = res.data;
        });
    }

    hasOneSaleSelected() {
        if (this.totalCheckedLines() === 1)
            return true;
        return false;
    }

    calculateSalePrice() {
        const sale = this.checkedLines()[0];
        const query = `Sales/${sale.id}/recalculatePrice`;
        this.$http.post(query).then(res => {
            this.vnApp.showSuccess(this.$translate.instant('Data saved!'));
            this.$scope.model.refresh();
        });
    }

    itemSearchFunc($search) {
        return /^\d+$/.test($search)
            ? {id: $search}
            : {name: {like: '%' + $search + '%'}};
    }
}

Controller.$inject = ['$scope', '$state', '$http', 'vnApp', '$translate'];

ngModule.component('vnTicketSale', {
    template: require('./index.html'),
    controller: Controller,
    bindings: {
        ticket: '<'
    },
    require: {
        card: '?^vnTicketCard'
    }
});