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 {copyFromBacklog, itemsUnfoldedList, nbrOccupiedSlotsInCrate, remove, reorder} from "./utils";

import {Layout} from "./Layout.jsx";
import {Backlog} from "./Backlog.jsx";
import {OrderPanel} from "./OrderPanel.jsx";
import {OrderSummary} from "./OrderSummary.jsx";
import {OrderForm} from "./OrderForm.jsx";
import {TriggerCrateWarnings, TriggerWarnings} from "./warnings";
import {FillResources} from "./count_resources";
import {CrateList} from "./CrateList.jsx";

/**
 * 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.onAddCrate = this.onAddCrate.bind(this);
        this.onDeleteCrate = this.onDeleteCrate.bind(this);
        this.onCrateModeChange = this.onCrateModeChange.bind(this);
        this.onCrateSelected = this.onCrateSelected.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: 'crate0',
            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.
         */
        console.log("componentDidUpdate")
        return;
        if (
            (prevState.columns.crates !== this.state.columns.crates.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);
    }

    onCrateChanged(crate_id) {
        // kinda silly that hover over cards triggers checkAlerts

        this.checkAlerts(crate_id)

    }

    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) {
        /**
         * 4 cases:
         * - from backlog to one of the crate - add to the correct crate in correct order
         * - from one crate to another - delete from one crate and put to another in correct order
         * - within one crate - reorder
         * - from crate to backlog - delete
         * */

        const {
            source,
            destination,
        } = result;
        /* better move to another function
        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]);
        }*/

        console.log('==> result', result);

        // dropped outside the list
        if (!destination) {
            return;
        }

        switch (source.droppableId) {
            // TODO add delete functionality
            case destination.droppableId:
                this.setState({
                    ...this.state,
                    columns: {
                        ...this.state.columns,
                        crates: {
                            ...this.state.columns.crates,
                            [destination.droppableId]: {
                                ...this.state.columns.crates[destination.droppableId],
                                items: reorder(
                                    this.state.columns.crates[source.droppableId].items,
                                    source.index,
                                    destination.index
                                )}}
                    }
                });
                this.onCrateChanged(destination.droppableId);
                break;
            case 'backlog':
                this.setState({
                    ...this.state,
                    columns: {
                        ...this.state.columns,
                        crates: {
                            ...this.state.columns.crates,
                            [destination.droppableId]: {
                                ...this.state.columns.crates[destination.droppableId],
                                items: copyFromBacklog(
                                    this.state.items,
                                    this.state.columns.crates[destination.droppableId],
                                    source,
                                    destination
                        )}}
                    }
                });
                this.onCrateChanged(destination.droppableId);
                break;
            default:
                this.setState({
                    columns: move(
                        this.state.columns[source.droppableId],
                        this.state.columns[destination.droppableId],
                        source,
                        destination
                    )
                });
                break;
        }
    }

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

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

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

        let itemsCloned = Array.from(this.state.columns.crates[crate_id].items);

        const crate_warnings = TriggerCrateWarnings(this.state.columns.crates[crate_id]);

        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);

        // update state with rules
        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                crates: {
                    ...this.state.columns.crates,
                    [crate_id]: {
                        ...this.state.columns.crates[crate_id],
                        items: itemsCloned,
                        warnings: crate_warnings
                    },
                }
            }
        });
    }

    onAddCrate(id) {
        this.setState({
            ...this.state,
            columns: {
                ...this.state.columns,
                crates: {
                    ...this.state.columns.crates,
                    [id]: {
                        crate_type: "rack",
                        items: []
                    }}
            }
        });
    }
    onDeleteCrate(id) {
        let new_state = {
            ...this.state,
            columns: {
                ...this.state.columns,
                crates: {
                    ...this.state.columns.crates,
                    [id]: undefined
                }
            }};
        delete new_state.columns.crates[id];
        this.setState(new_state);
    }

    onCrateSelected(id) {
        console.log(id)
        this.setState({
            active_crate: id
        })
    }

    onCrateModeChange(crate_id, new_mode) {
        let new_state = {
            ...this.state,
            columns: {
                ...this.state.columns,
                crates: {
                    ...this.state.columns.crates,
                    [crate_id]: {
                        ...this.state.columns.crates[crate_id],
                        crate_type: new_mode
                    }
                }
            }};
        this.setState(new_state);
    }

    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>)}
                            cratesList={
                                <CrateList
                                    crates={columns.crates}
                                    isTouch={isTouch}
                                    isMobile={isMobile}
                                    onAddCrate={this.onAddCrate}
                                    onDeleteCrate={this.onDeleteCrate}
                                    onModeChange={this.onCrateModeChange}
                                    onCrateSelect={this.onCrateSelected}
                                    active_crate={this.state.active_crate}
                                />
                            }
                            summaryPrice={
                                <OrderSummary
                                    currency={currency}
                                    crates={columns.crates}
                                    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>
        );
    }
}