import ngModule from '../module';
import Section from 'salix/components/section';
import './style.scss';

class Controller extends Section {
    constructor($element, $) {
        super($element, $);
        this._sales = [];
        this.manaCode = 'mana';
        this.getConfig();
    }

    sortBy(propertyName) {
        this.reverse = (this.propertyName === propertyName) ? !this.reverse : false;
        this.propertyName = propertyName;
    }

    get manaCode() {
        return this._manaCode;
    }

    set manaCode(value) {
        this._manaCode = value;
    }

    get ticket() {
        return this._ticket;
    }

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

    get sales() {
        if (this._sales) {
            for (let sale of this._sales)
                sale.amount = this.getSaleTotal(sale);
        }

        return this._sales;
    }

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

    get ticketState() {
        const ticket = this.ticket;
        if (!ticket) return null;

        const ticketState = ticket.ticketState;

        return ticketState && ticketState.state.code;
    }

    getConfig() {
        let filter = {
            fields: ['daysForWarningClaim'],
        };
        this.$http.get(`TicketConfigs`, {filter})
            .then(res => {
                this.ticketConfig = res.data;
            });
    }

    get isClaimable() {
        if (this.ticket) {
            const landedPlusWeek = new Date(this.ticket.landed);
            landedPlusWeek.setDate(landedPlusWeek.getDate() + 7);

            const hasClaimManagerRole = this.aclService.hasAny(['claimManager']);

            return landedPlusWeek >= Date.vnNew() || hasClaimManagerRole;
        }
        return false;
    }

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

        const price = sale.quantity * sale.price;
        const discount = (sale.discount * price) / 100;

        return price - discount;
    }

    getMana() {
        this.$http.get(`Tickets/${this.$params.id}/getSalesPersonMana`)
            .then(res => {
                this.edit.mana = res.data;
                this.$.$applyAsync(() => {
                    this.$.editDiscount.relocate();
                    this.$.editPricePopover.relocate();
                });
            });
        this.getUsesMana();
    }

    getUsesMana() {
        this.$http.get(`Sales/usesMana`)
            .then(res => {
                this.usesMana = res.data;
            });
    }

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

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

    selectedValidSales() {
        if (!this.sales) return;

        const selectedSales = this.selectedSales();
        return selectedSales.filter(sale => {
            return sale.id != undefined;
        });
    }

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

        return 0;
    }

    hasSelectedSales() {
        return this.selectedSalesCount() > 0;
    }

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

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

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

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

        this.card.reload();
    }

    state(value) {
        const params = {ticketFk: this.$params.id, code: value};
        return this.$http.post('Tickets/state', params).then(() => {
            this.vnApp.showSuccess(this.$t('Data saved!'));
            this.card.reload();
        }).finally(() => this.resetChanges());
    }

    removeSales() {
        const sales = this.selectedValidSales();
        const params = {sales: sales, ticketId: this.ticket.id};
        this.$http.post(`Sales/deleteSales`, params).then(() => {
            this.removeSelectedSales();
            this.vnApp.showSuccess(this.$t('Data saved!'));
        }).finally(() => this.resetChanges());
    }

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

    createClaim() {
        const today = new Date();
        today.setHours(0, 0, 0, 0);
        const timeDifference = today.getTime() - new Date(this.ticket.landed).getTime();

        const pastDays = Math.floor(timeDifference / 86400000);

        if (pastDays >= this.ticketConfig[0].daysForWarningClaim)
            this.$.claimConfirm.show();
        else
            this.$.claimSure.show();
    }

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

    showTransferPopover(event) {
        this.setTransferParams();
        this.$.transfer.show(event);
    }

    setTransferParams() {
        const checkedSales = JSON.stringify(this.selectedValidSales());
        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.$.watcher.updateOriginalData();

        const query = `tickets/${this.ticket.id}/transferSales`;
        this.$http.post(query, params)
            .then(res => {
                if (res.data && res.data.id === this.ticket.id) {
                    this.$.transfer.hide();
                    this.$.model.refresh();
                } else this.$state.go('ticket.card.sale', {id: res.data.id});
            });
    }

    showEditPricePopover(event, sale) {
        if (!this.isEditable) return;

        this.edit = {
            price: sale.price,
            sale: sale
        };
        this.$.editPricePopover.show(event);
    }

    updatePrice() {
        const sale = this.edit.sale;
        const newPrice = this.edit.price;
        if (newPrice != null && newPrice != sale.price) {
            const query = `Sales/${sale.id}/updatePrice`;
            this.$http.post(query, {newPrice}).then(res => {
                sale.price = res.data.price;
                this.edit = null;
                this.vnApp.showSuccess(this.$t('Data saved!'));
            }).finally(() => this.resetChanges());
        }

        this.$.editPricePopover.hide();
    }

    showEditDiscountPopover(event, sale) {
        if (this.isLocked) return;
        if (sale) {
            this.edit = {
                discount: sale.discount,
                sale: sale
            };
        } else {
            this.edit = {
                discount: null,
                sales: this.selectedValidSales()
            };
        }

        this.$.editDiscount.show(event);
    }

    changeDiscount() {
        const sale = this.edit.sale;
        const newDiscount = this.edit.discount;
        if (newDiscount != null && newDiscount != sale.discount)
            this.updateDiscount([sale]);

        this.$.editDiscount.hide();
    }

    changeMultipleDiscount() {
        const sales = this.edit.sales;
        const newDiscount = this.edit.discount;
        const hasChanges = sales.some(sale => {
            return sale.discount != newDiscount;
        });
        if (newDiscount != null && hasChanges)
            this.updateDiscount(sales);

        this.$.editDiscount.hide();
    }

    updateDiscount(sales) {
        const saleIds = sales.map(sale => {
            return sale.id;
        });

        const params = {salesIds: saleIds, newDiscount: this.edit.discount, manaCode: this.manaCode};
        const query = `Tickets/${this.$params.id}/updateDiscount`;
        this.$http.post(query, params).then(() => {
            this.vnApp.showSuccess(this.$t('Data saved!'));

            for (let sale of sales)
                sale.discount = this.edit.discount;

            this.edit = null;
        }).finally(() => this.resetChanges());
    }

    getNewPrice() {
        if (this.edit.sale) {
            const sale = this.edit.sale;
            let newDiscount = sale.discount;
            let newPrice = this.edit.price || sale.price;

            if (this.edit.discount != null)
                newDiscount = this.edit.discount;

            if (this.edit.price != null)
                newPrice = this.edit.price;

            const price = sale.quantity * newPrice;
            const discount = (newDiscount * price) / 100;

            return price - discount;
        }

        return 0;
    }

    hasReserves() {
        return this.sales.some(sale => {
            return sale.reserved == true;
        });
    }

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

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

    setReserved(reserved) {
        const selectedSales = this.selectedValidSales();
        const params = {ticketId: this.ticket.id, sales: selectedSales, reserved: reserved};
        this.$http.post(`Sales/reserve`, params).then(() => {
            selectedSales.forEach(sale => {
                sale.reserved = reserved;
            });
        }).finally(() => this.resetChanges());
    }

    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.$t('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.selectedValidSales();
        const items = sales.map(sale => {
            return `${sale.quantity} ${sale.concept}`;
        });
        const notAvailables = items.join(', ');
        const params = {
            ticketFk: this.ticket.id,
            created: this.ticket.updated,
            landed: this.ticket.landed,
            notAvailables
        };
        this.newSMS = {
            ticketId: this.ticket.id,
            destinationFk: this.ticket.clientFk,
            destination: phone,
            message: this.$t('Product not available', params)
        };
        this.$.sms.open();
    }

    onSmsSend(sms) {
        return this.$http.post(`Tickets/${this.ticket.id}/sendSms`, sms)
            .then(() => this.vnApp.showSuccess(this.$t('SMS sent')));
    }

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

    /*
     * Creates a new sale if it's a new instance
     * Updates the sale quantity for existing instance
     */
    changeQuantity(sale) {
        if (!sale.itemFk || sale.quantity == null) return;

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

        this.updateQuantity(sale);
    }

    /*
     * Changes a sale quantity
     */
    updateQuantity(sale) {
        const data = {quantity: sale.quantity};
        this.$http.post(`Sales/${sale.id}/updateQuantity`, data).then(() => {
            this.vnApp.showSuccess(this.$t('Data saved!'));
        }).catch(e => {
            this.$.model.refresh();
            throw e;
        }).finally(() => this.resetChanges());
    }

    /*
     * Changes a sale concept
     */
    updateConcept(sale) {
        const data = {newConcept: sale.concept};
        this.$http.post(`Sales/${sale.id}/updateConcept`, data).then(() => {
            this.vnApp.showSuccess(this.$t('Data saved!'));
        }).catch(e => {
            this.$.model.refresh();
            throw e;
        }).finally(() => this.resetChanges());
    }

    /*
     * 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.$t('Data saved!'));
        }).finally(() => this.resetChanges());
    }

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

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

    calculateSalePrice() {
        const sales = this.selectedValidSales();
        if (!sales) return;

        const query = `Sales/recalculatePrice`;
        this.$http.post(query, sales).then(() => {
            this.vnApp.showSuccess(this.$t('Data saved!'));
            this.$.model.refresh();
        });
    }

    createRefund(withWarehouse) {
        const sales = this.selectedValidSales();
        if (!sales) return;

        const salesIds = sales.map(sale => sale.id);
        const params = {salesIds: salesIds, withWarehouse: withWarehouse};
        const query = 'Sales/refund';
        this.$http.post(query, params).then(res => {
            const refundTicket = res.data;
            this.vnApp.showSuccess(this.$t('The following refund ticket have been created', {
                ticketId: refundTicket.id
            }));
            this.$state.go('ticket.card.sale', {id: refundTicket.id});

            this.resetChanges();
        });
    }

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

    save() {
        if (this.edit.sale) this.changeDiscount();
        if (this.edit.sales) this.changeMultipleDiscount();
    }

    cancel() {
        this.$.editDiscount.hide();
    }

    goToLog(saleId) {
        this.$state.go('ticket.card.log', {
            originId: this.$params.id,
            changedModel: 'Sale',
            changedModelId: saleId
        });
    }
}

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