import React, {PureComponent} from 'react';
import PropTypes from "prop-types";
import {FilterOptions} from "./options/utils";
import {v4 as uuidv4} from "uuid";
import {DragDropContext} from "@hello-pangea/dnd";

import {copy, itemsUnfoldedList, nbrOccupiedSlotsInCrate, remove, reorder} from "./utils";

import {Layout} from "./Layout.jsx";
import {Backlog} from "./Backlog.jsx";
import {OrderPanel} from "./OrderPanel.jsx";
import {CrateMode} from "./CrateMode.jsx";
import {Crate} from "./Crate.jsx";
import {Cart} from "./Cart.jsx";
import {OrderSummary} from "./OrderSummary.jsx";
import {OrderForm} from "./OrderForm.jsx";
import {TriggerWarnings} from "./warnings";
import {FillResources} from "./count_resources";

/**
 * Component that render the entire shop
 */

export class Shop extends PureComponent {

    static get propTypes() {
        return {
            data: PropTypes.object.isRequired,
        };
    }

    constructor(props) {
        super(props);
        this.state = this.props.data;
        this.handleCrateModeChange = this.handleCrateModeChange.bind(this);
        this.handleOnDragEnd = this.handleOnDragEnd.bind(this);
        this.handleDeleteItem = this.handleDeleteItem.bind(this);
        this.handleDeleteAllItems = this.handleDeleteAllItems.bind(this);
        this.handleMouseEnterItem = this.handleMouseEnterItem.bind(this);
        this.handleMouseLeaveItem = this.handleMouseLeaveItem.bind(this);
        this.handleClickAddItem = this.handleClickAddItem.bind(this);
        this.checkAlerts = this.checkAlerts.bind(this);
        this.handleClickSelectItem = this.handleClickSelectItem.bind(this);
        this.handleClickSubmit = this.handleClickSubmit.bind(this);
        this.handleToggleOverlayRemove = this.handleToggleOverlayRemove.bind(this);
        this.handleShowOverlayRemove = this.handleShowOverlayRemove.bind(this);
        this.handleClickToggleMobileSideMenu = this.handleClickToggleMobileSideMenu.bind(this);
        this.handleClickCloseRFQFeedback = this.handleClickCloseRFQFeedback.bind(this);
        this.handleClickShowOrder = this.handleClickShowOrder.bind(this);
        this.handleClickOpenImport = this.handleClickOpenImport.bind(this);
        this.handleLoadCustomConf = this.handleLoadCustomConf.bind(this);
        this.handleCardsUpdated = this.handleCardsUpdated.bind(this);

        this.timer = null;
        this.timer_remove = null;
    }

    componentDidMount() {
        const source = {
            droppableId: 'backlog',
            indexes: [
                itemsUnfoldedList.findIndex(element => element === "eem_pwr_mod"),
                itemsUnfoldedList.findIndex(element => element === "kasli")
            ],
        };
        const destination = {
            droppableId: 'cart',
            index: 0,
        };

        this.handleOnDragEnd({
            source,
            destination
        });
    }

    componentDidUpdate(prevProps, prevState) {
        /**
         * We check alerts (reminder + warning) only when items inside crate or
         * crate mode change.
         *
         * In the function checkAlerts, we DO NOT want to change items as we will
         * trigger again this function (componentDidUpdate) and thus,
         * making an infinite loop.
         */
        if (
            (prevState.columns.cart.items !== this.state.columns.cart.items) ||
            (prevState.currentMode !== this.state.currentMode)
        ) {
            this.checkAlerts(this.state.columns.cart.items);
        }

        if (this.state.newCardJustAdded) {
            this.timer = setTimeout(() => {
                this.setState({
                    newCardJustAdded: false,
                });
            }, 2000);
        }
    }

    componentWillUnmount() {
        clearTimeout(this.timer);
    }

    handleCardsUpdated() {
        this.checkAlerts(this.state.columns.cart.items);
    }

    handleCrateModeChange(mode) {
        this.setState({
            currentMode: mode,
        });
    }

    handleDeleteItem(index) {
        let cloned = Array.from(this.state.columns.cart.items);
        let cloned_data = Array.from(this.state.columns.cart.itemsData);
        cloned.splice(index, 1);
        cloned_data.splice(index, 1);

        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                cart: {
                    ...this.state.columns.cart,
                    items: cloned,
                    itemsData: cloned_data,
                },
            },
        });
    }

    handleDeleteAllItems() {
        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                cart: {
                    ...this.state.columns.cart,
                    items: [],
                    itemsData: []
                },
            },
        });
    }

    handleMouseEnterItem(id) {
        this.setState({
            ...this.state,
            currentItemHovered: id,
        });
    }

    handleMouseLeaveItem() {
        this.setState({
            ...this.state,
            currentItemHovered: null,
        });
    }

    handleClickAddItem(index, tap) {
        const source = {
            droppableId: 'backlog',
            index: index,
        };
        const destination = {
            droppableId: 'cart',
            index: this.state.columns.cart.items.length,
        };

        this.handleOnDragEnd({
            source,
            destination
        }, tap);
    }

    handleClickSelectItem(index) {
        const itemsCloned = Array.from(this.state.columns.cart.items);

        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                cart: {
                    ...this.state.columns.cart,
                    items: itemsCloned.map((item, id) => {
                        return {...item, selected: id === index ? true : false};
                    }),
                }
            },
        });
    }

    handleToggleOverlayRemove(index, show) {
        const itemsCloned = Array.from(this.state.columns.cart.items);

        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                cart: {
                    ...this.state.columns.cart,
                    items: itemsCloned.map((item, id) => {
                        return {
                            ...item,
                            showOverlayRemove: id === index ? show : false
                        };
                    }),
                }
            },
        });
    }

    handleShowOverlayRemove(index) {
        if (this.timer_remove)
            clearTimeout(this.timer_remove);

        this.handleToggleOverlayRemove(index, true);

        this.timer_remove = setTimeout(() => {
            this.handleToggleOverlayRemove(index, false);
        }, 2000);
    }

    handleClickShowOrder() {
        const crate = {
            items: [],
            type: this.state.currentMode,
        };
        const clonedCart = Array.from(this.state.columns.cart.items);
        const clonedCartData = Array.from(this.state.columns.cart.itemsData);
        for (const i in clonedCart) {
            const item = clonedCart[i];
            const item_data = clonedCartData[i];
            crate.items.push({
                'pn': item.name_number,
                'options': (item_data.options_data && item_data.options) ? FilterOptions(item_data.options, item_data.options_data) : null,
            });
        }

        this.setState({
            isProcessing: false,
            shouldShowRFQFeedback: true,
            RFQBodyType: 'show',
            RFQBodyOrder: JSON.stringify(crate, null, 2),
        });
    }

    handleClickOpenImport() {
        this.setState({
            isProcessing: false,
            shouldShowRFQFeedback: true,
            RFQBodyType: 'import',
        });
    }

    handleLoadCustomConf(customconf) {
        if (!customconf) {return; }

        const items = this.props.data.items;

        let new_items = [];
        let new_items_data = [];


        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                cart: {
                    ...this.state.columns.cart,
                    items: [],
                },
            },
        }, function () {

            customconf.items.map(function (item) {
                Object.keys(items).map(key => {
                    if (item.pn && item.pn === items[key].name_number) {
                        new_items.push(Object.assign({
                            ...items[key],
                        }, {
                            id: uuidv4(),
                            options_data: item.options ? item.options : null,
                        }));
                        new_items_data.push({options_data: item.options ? item.options : null});
                    }
                });

                return item;
            });

            this.setState({
                ...this.state,
                columns: {
                    ...this.state.columns,
                    cart: {
                        ...this.state.columns.cart,
                        items: new_items,
                        itemsData: new_items_data,
                    },
                },
                currentMode: customconf.type,
            });
        });
    }

    handleClickSubmit(note, email) {
        const crate = {
            items: [],
            type: this.state.currentMode,
        };
        const clonedCart = Array.from(this.state.columns.cart.items);
        const clonedCartData = Array.from(this.state.columns.cart.itemsData);
        for (const i in clonedCart) {
            const item = clonedCart[i];
            const item_data = clonedCartData[i];
            crate.items.push({
                'pn': item.name_number,
                'options': (item_data.options_data && item_data.options) ? FilterOptions(item_data.options, item_data.options_data) : null,
            });
        }

        const {data} = this.props;

        this.setState({isProcessing: true});

        fetch(data.API_RFQ, {
            method: "POST",
            headers: {'Content-Type': 'application/json'},
            body: JSON.stringify({
                email,
                note,
                configuration: JSON.stringify(crate)
            })
        }).then(response => {
            if (response.status !== 200) {
                throw Error("Response status is not OK: " + response.status + ".\n" + response);
            }
            this.setState({
                isProcessing: false,
                shouldShowRFQFeedback: true,
                RFQBodyType: 'email',
                isProcessingComplete: true,
            });
        }).catch(err => {
            console.error("Request failed, reason:", err)
            this.setState({isProcessing: false}, () => {
                alert("We cannot receive your request. Try using the export by coping the configuration and send it to us at sales@m-labs.hk");
            });
        })
    }

    handleOnDragEnd(result, newAdded) {
        const {
            source,
            destination,
        } = result;
        let dragged_items = [];
        if (source.indexes) {
            source.indexes.forEach((card_index, _) => {
                dragged_items.push(itemsUnfoldedList[card_index]);
            })
        } else if (source.index >= 0) {
            dragged_items.push(itemsUnfoldedList[source.index]);
        }


        if (!destination) {
            if (source.droppableId === 'cart') {
                this.setState({
                    ...this.state,
                    newCardJustAdded: false,
                    columns: {
                        ...this.state.columns,
                        [source.droppableId]: {
                            ...this.state.columns[source.droppableId],
                            items: remove(
                                this.state.columns[source.droppableId].items,
                                source.index,
                            ),
                            itemsData: remove(
                                this.state.columns[source.droppableId].itemsData,
                                source.index,
                            )
                        },
                    },
                });
            }

            return;
        }

        switch(source.droppableId) {

            case 'backlog':
                if (source.droppableId !== destination.droppableId) {
                    this.setState({
                        ...this.state,
                        newCardJustAdded: newAdded ? true : false,
                        columns: {
                            ...this.state.columns,
                            [destination.droppableId]: {
                                ...this.state.columns[destination.droppableId],
                                items: copy(
                                    this.state.items,
                                    this.state.columns[source.droppableId],
                                    this.state.columns[destination.droppableId],
                                    dragged_items,
                                    destination,
                                ),
                            },
                        },
                    });
                }
                break;

            case destination.droppableId:
                this.setState({
                    ...this.state,
                    newCardJustAdded: false,
                    columns: {
                        ...this.state.columns,
                        [destination.droppableId]: {
                            ...this.state.columns[destination.droppableId],
                            items: reorder(
                                this.state.columns[destination.droppableId].items,
                                source.index,
                                destination.index,
                            ),
                            itemsData: reorder(
                                this.state.columns[destination.droppableId].itemsData,
                                source.index,
                                destination.index,
                            ),
                        },
                    },
                });
                break;

            default:
                break;
        }
    }

    handleClickToggleMobileSideMenu() {
        this.setState({
            ...this.state,
            mobileSideMenuShouldOpen: !this.state.mobileSideMenuShouldOpen,
        });
    }

    handleClickCloseRFQFeedback() {
        this.setState({
            shouldShowRFQFeedback: false,
        });
    }

    checkAlerts(newItems) {
        console.log('--- START CHECKING CRATE WARNING ---');

        const {
            currentMode,
            crateModeSlots,
            crateRules,
        } = this.state;

        let itemsCloned = Array.from(newItems);
        const rules = {};

        itemsCloned.forEach((elem, idx) => {
            if (!(idx in itemsCloned)) itemsCloned[idx] = elem;
            if (idx in this.state.columns.cart.itemsData && this.state.columns.cart.itemsData[idx].options_data) {
                itemsCloned[idx].options_data = this.state.columns.cart.itemsData[idx].options_data;
            }
        });

        itemsCloned = FillResources(itemsCloned);
        itemsCloned = TriggerWarnings(itemsCloned);

        // check number of slot in crate
        const nbrOccupied = nbrOccupiedSlotsInCrate(newItems);
        if (nbrOccupied > crateModeSlots[currentMode]) {
            rules[crateRules.maxSlot.type] = {...crateRules.maxSlot};
        } else if (crateModeSlots[currentMode] === 21 && nbrOccupied <= 10) {
            rules[crateRules.compactSlot.type] = {...crateRules.compactSlot};
        }

        // update state with rules
        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                cart: {
                    ...this.state.columns.cart,
                    itemsData: itemsCloned,
                }
            },
            rules: {
                ...rules,
            },
        });
    }

    render() {

        const {
            currency,
            currentItemHovered,
            currentMode,
            crateModeSlots,
            crateModeItems,
            items,
            columns,
            rules,
            mobileSideMenuShouldOpen,
            newCardJustAdded,
            isProcessing,
            shouldShowRFQFeedback,
            RFQBodyType,
            RFQBodyOrder,
            isProcessingComplete,
        } = this.state;

        const isMobile = window.deviceIsMobile();
        const isTouch = window.isTouchEnabled();

        return (
            <DragDropContext onDragEnd={this.handleOnDragEnd}>

                <Layout
                    showRFQFeedback={shouldShowRFQFeedback}
                    RFQBodyType={RFQBodyType}
                    RFQBodyOrder={RFQBodyOrder}
                    className="shop"
                    mobileSideMenuShouldOpen={mobileSideMenuShouldOpen}
                    isMobile={isMobile}
                    newCardJustAdded={newCardJustAdded}
                    onClickToggleMobileSideMenu={this.handleClickToggleMobileSideMenu}
                    onClickCloseRFQFeedback={this.handleClickCloseRFQFeedback}
                    onClickLoadCustomConf={this.handleLoadCustomConf}
                    items={items}
                    aside={
                        <Backlog
                            currency={currency}
                            items={items}
                            data={columns['backlog']}
                            onClickAddItem={this.handleClickAddItem}
                            onClickToggleMobileSideMenu={this.handleClickToggleMobileSideMenu}
                            isMobile={isMobile}>
                        </Backlog>
                    }
                    main={(
                        <OrderPanel
                            onClickToggleMobileSideMenu={this.handleClickToggleMobileSideMenu}
                            onClickOpenImport={this.handleClickOpenImport}
                            isMobile={isMobile}
                            title="Order hardware"
                            description={(<p className="description">Drag and drop the cards you want into the crate below to see how the combination would look like. Setup card's configuration by tapping at the top of the card, most of the options can be modified after shipment. If you have any issues with this ordering system, or if you need other configurations, email us directly anytime at <a href="mailto:sales@m-labs.hk">sales@m-labs.hk</a>. The price is estimated and must be confirmed by a quote.</p>)}
                            crateMode={
                                <CrateMode
                                    items={crateModeItems}
                                    mode={currentMode}
                                    onClickMode={this.handleCrateModeChange}>
                                </CrateMode>}
                            crate={
                                <Crate
                                    cart={
                                        <Cart
                                            nbrSlots={crateModeSlots[currentMode]}
                                            data={columns['cart']}
                                            isMobile={isMobile}
                                            isTouch={isTouch}
                                            itemHovered={currentItemHovered}
                                            onToggleOverlayRemove={this.handleToggleOverlayRemove}
                                            onClickRemoveItem={this.handleDeleteItem}
                                            onClickItem={this.handleShowOverlayRemove}
                                            onCardUpdate={this.handleCardsUpdated}>
                                        </Cart>
                                    }
                                    rules={Object.values(rules).filter(rule => rule)}>
                                </Crate>
                            }
                            summaryPrice={
                                <OrderSummary
                                    currency={currency}
                                    currentMode={currentMode}
                                    modes={crateModeItems}
                                    summary={columns['cart'].items}
                                    itemsData={columns.cart.itemsData}
                                    onMouseEnterItem={this.handleMouseEnterItem}
                                    onMouseLeaveItem={this.handleMouseLeaveItem}
                                    onDeleteItem={this.handleDeleteItem}
                                    onDeleteAllItems={this.handleDeleteAllItems}
                                    onClickSelectItem={this.handleClickSelectItem}>
                                </OrderSummary>
                            }
                            form={
                                <OrderForm
                                    isProcessingComplete={isProcessingComplete}
                                    processingComplete={this.handleProcessingComplete}
                                    isProcessing={isProcessing}
                                    onClickSubmit={this.handleClickSubmit}
                                    onClickShow={this.handleClickShowOrder}>
                                </OrderForm>
                            }>
                        </OrderPanel>
                    )}>
                </Layout>

            </DragDropContext>
        );
    }
}