import React from 'react';
import superagent from 'superagent';

import { fromUnixTime, formatDistanceToNow } from "date-fns";
import { formatInTimeZone } from 'date-fns-tz';
import { DEFAULT_TIMEZONE } from '../CloudApi/Constants.js';

import { Accordion, Header, Message, Icon, Button, Table, Segment, Modal, Statistic, Image, Step, Transition } from 'semantic-ui-react';

import * as ApiUtils from '../CloudApi/ApiUtils.js';
import ApiButtonModal from '../CloudApi/ApiButtonModal.jsx';
import BigShipperWrapper from './BigShipperWrapper.jsx';
import BigOrderComponent from '../BigOrders/BigOrderComponent.jsx';
import HandScannerInput from '../Util/HandScannerInput.jsx';
import BigShipmentInventoryCards from './BigShipmentInventoryCards.jsx';
import BigShipmentLabel from './BigShipmentLabel.jsx';
import BigApiErrorMessage from '../CloudApi/BigApiErrorMessage.jsx';
import InventoryItemsTable from './InventoryItemsTable.jsx';

export default class BigShipment extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            bigShipment: null,
            instantLabelPrinting: true, /* Will automatically generate and print the label once all items picked. */
            labelTimerSeconds: 2.5,
            isLabelPrintTimerActive: false,
            showPickingCompleteDialog: false,
            infoActiveIndex: 0,
            error: null
        };
    }

    async componentDidMount() {
        await this.reload();
    }

    async reload() {
        this.setState({ loading: true, error: null, packingLabelScanned: false, packingLabelScanned2: false });
        try {
            let schemas = await ApiUtils.getFabricatorSchemas();
            this.setState({ schemas });

            const res = await superagent.get(`/api/admin/shipper/shipment/${this.props.match.params.id}`).accept('json');
            let newState = {
                bigShipment: res.body.bigShipment,
                bigOrder: res.body.bigOrder,
                inventoryItems: res.body.inventoryItems,
                pickingHints: res.body.pickingHints
            }
            console.log(res.body);

            if (res.body.error) {
                newState.bigShipmentError = res.body.error;
            }
            this.setState(newState);

            if (res.body.bigShipment.status === "PrepareShippingLabel") {
                this.startLabelPrintTimer();
            }
        } catch (e) {
            console.log(e);
        }

        this.setState({ loading: false });
    }

    async onReload() {
        await this.reload();
    }

    renderTestStatus() {
        const shopifyOrder = this.state.bigOrder.shopifyOrderSnapshot;
        if (shopifyOrder.tags.includes("test order") || shopifyOrder.test === true) {
            return (
                <Segment inverted color="red">
                    <Icon name="dont" />This is a test order. BE CAREFUL WITH SHIPPING THIS ORDER!<Icon name="dont" />
                </Segment>
            );
        }

        return null;
    }

    renderShipmentStatus() {
        let segmentColor = "green";
        let icon = "warning circle";
        // TODO: use a fucking switch
        if (this.state.bigShipment.status === "Picking") {
            segmentColor = "orange";
        } else if (this.state.bigShipment.status === "ReadyToPack") {
            segmentColor = "orange";
        } else if (this.state.bigShipment.status === "Packing") {
            segmentColor = "orange";
        } else if (this.state.bigShipment.status === "PreparingToShip") {
            segmentColor = "orange";
        } else if (this.state.bigShipment.status === "PackedAndLabelled") {
            segmentColor = "orange";
        } else if (this.state.bigShipment.status === "WaitingForPickup") {
            segmentColor = "green";
        } else if (this.state.bigShipment.status === "InTransit") {
            segmentColor = "orange";
        } else if (this.state.bigShipment.status === "Shipped") {
            segmentColor = "green";
            icon = "checkmark";
        } else if (this.state.bigShipment.status === "DeliveryFailed") {
            segmentColor = "red";
        } else if (this.state.bigShipment.status === "Cancelled") {
            segmentColor = "red";
        }

        // HACK HACK HACK
        if (segmentColor == "orange") {
            return null;
        }

        return (
            <Message color={segmentColor} icon warning>
                <Icon name={icon} />
                <Message.Content>
                    <Message.Header>Status: {this.state.bigShipment.status}</Message.Header>
                </Message.Content>
            </Message>
        );
    }

    async onScanSerialNumberPicking(scannedSerialNumber) {
        if (scannedSerialNumber.startsWith("bs")) {
            scannedSerialNumber = scannedSerialNumber.toUpperCase();
        }

        this.setState({ loading: true, scannedSerialNumber: "" });
        try {
            const res = await superagent.get(`/api/admin/inventory/items?prefixSerialNumber=${scannedSerialNumber}`);
            if (res.body.items.length === 1) {
                let inventoryItemId = res.body.items[0].id;
                const res2 = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                    .send({
                        action: "PickInventoryItem",
                        inventoryItemId
                    });

                const audio = new Audio("/misc/Notification3_2.wav");
                audio.play();
                await this.reload();

                if (this.state.instantLabelPrinting === true) {
                    if (this.state.bigShipment.inventoryItemIds.length === this.state.bigShipment.inventorySlots.length) {
                        this.setState({ isLabelPrintTimerActive: true });
                        this.timer = setInterval(this.instantLabelTimerTick.bind(this), 500);
                    }
                }
            } else {
                console.log("No inventory item found for serial number", scannedSerialNumber);
                const audio = new Audio("/misc/Error1.wav");
                audio.play();
            }
        } catch (e) {
            console.log(e);
            this.setState({ error: e });
        }

        this.setState({ loading: false });
    }

    async onAddAccessoryInventoryItem(inventorySlot) {
        this.setState({ loading: true });

        const res2 = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
            .send({
                action: "PickInventoryItem",
                inventorySlotId: inventorySlot.id,
            });

        const audio = new Audio("/misc/Notification3_2.wav");
        audio.play();
        await this.reload();
        this.setState({ loading: false });
    }

    async onPrepareShipping() {
        this.setState({ loading: true });
        try {
            const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                .send({
                    action: "FinishPicking"
                });
            await this.reload();
        } catch (e) {
            console.log(e);
        }
        this.setState({ loading: false });
    }

    async onGenerateShippingLabel() {
        this.setState({ loading: true, error: null });
        try {
            const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                .send({
                    action: "GenerateShippingLabel"
                });
            await this.setState({ bigShipment: res.body.shipment });
            await this.reload();
        } catch (ex) {
            this.setState({ error: ex });
            console.log(ex);
        }
        this.setState({ loading: false });
    }

    async onStartShippingLabelCountdown() {
        this.setState({ isLabelPrintTimerActive: true });
        this.timer = setInterval(this.instantLabelTimerTick.bind(this), 500);
    }

    async instantLabelTimerTick() {
        if (this.state.isLabelPrintTimerActive && this.state.labelTimerSeconds > 0) {
            this.setState({ labelTimerSeconds: this.state.labelTimerSeconds - 0.5 });
        } else if (this.state.labelTimerSeconds <= 0) {
            clearInterval(this.timer);
            await this.onPrepareShipping();
            await this.onGenerateShippingLabel();
            const audio = new Audio("/misc/Notification24.wav");
            audio.play();
        }
    }


    async onStartPacking() {
        this.setState({ loading: true });
        try {
            const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                .send({
                    action: "StartPacking"
                });
            console.log("onGenerateShippingLabel", res.body);
            await this.setState({ bigShipment: res.body.shipment });
            await this.reload();
        } catch (e) {
            console.log(e);
        }
        this.setState({ loading: false });
    }

    async onCalculateShippingRates() {
        this.setState({ loading: true });
        try {
            const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                .send({
                    action: "CalculateShippingRates"
                });
            console.log("onCalculateShippingRates", res.body);
            await this.setState({ shippingRates: res.body.shippingRates });
            await this.reload();
        } catch (e) {
            console.log(e);
        }
        this.setState({ loading: false });
    }

    async onSelectShippingRate(shippingRate) {
        const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
            .send({
                action: "SetShippingRate",
                shippingRateId: shippingRate.object_id
            });
        console.log("onSelectShippingRate", res.body);
        await this.setState({ shippingRates: res.body.shippingRates });
        await this.reload();
    }

    async onCancelShipment() {
        this.setState({ loading: true, error: null });
        try {
            const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                .send({
                    action: "Cancel"
                });
            await this.setState({ bigShipment: res.body.shipment, showCancelShipmentModal: false });
            await this.reload();
        } catch (ex) {
            this.setState({ error: ex });
            console.log(ex);
        }
        this.setState({ loading: false });
    }

    renderCancelShipmentModal() {
        return (
            <Modal dimmer="inverted" closeOnEscape={true} closeOnDimmerClick={true} closeIcon
                onClose={() => this.setState({ showCancelShipmentModal: false })}
                open={this.state.showCancelShipmentModal}>
                <Header icon='user' content='Cancel this shipment?' />
                <Modal.Content>
                    <Header as='h1'>BE CAREFUL! THIS IS NOT THE USUAL YADA YADA</Header>

                    {this.state.bigShipment.currentShippingLabel && <>
                        <Header as="h2"><a style={{ 'textDecoration': 'underline' }} href={this.state.bigShipment.currentShippingLabel.tracking_url_provider}>This shipment has a shipping label!</a></Header>
                        <Message icon error>
                            <Icon name='warning sign' />
                            <Message.Content>
                                <Message.Header as="h1">IF A LABEL HAS PRINTED - PLEASE CHECK IF THE LABEL HAS BEEN USED ON SHIPPO OR SHOPIFY.</Message.Header>
                                If the label has been used, you need to reprint the label and scan it in to fulful the shipment here. <strong>Do not cancel this shipment if this is the case!</strong>
                            </Message.Content>
                        </Message>

                        <Message icon error>
                            <Icon name='warning sign' />
                            <Message.Content>
                                <Message.Header as="h1">If the label has printed, only an admin can cancel this shipment.</Message.Header>
                            </Message.Content>
                        </Message>
                    </>}

                    <Message icon warning>
                        <Icon name='warning circle' />
                        <Message.Content>
                            <Message.Header as="h1">You can safely cancel this shipment if:</Message.Header>
                            <ul>
                                <li>The items have not shipped.</li>
                                <li>There is a shipping label, but it has not been printed or shown as "with carrier".</li>
                                <li>There is no box waiting to be picked up at the factory.</li>
                            </ul>
                        </Message.Content>
                    </Message>

                    <Message icon warning>
                        <Icon name='warning circle' />
                        <Message.Content>
                            <Message.Header as="h1">All items in this shipment must be returned to inventory!</Message.Header>
                        </Message.Content>
                    </Message>
                </Modal.Content>

                <Modal.Actions>
                    <Button color='red' loading={this.state.loading} onClick={this.onCancelShipment.bind(this)}>
                        <Icon name='trash' />Yes, Cancel Shipment
                    </Button>
                </Modal.Actions>
            </Modal>
        )
    }

    renderNextStepButton(text, fn) {
        return (
            <div style={{ marginTop: "10px", marginBottom: "10px" }}><Button color="green" icon onClick={fn}>{text} <Icon name="arrow alternate circle right" /></Button></div>
        )
    }

    renderPickingStage() {
        const nextStepButton = this.renderNextStepButton("Next: Print Shipping Label", this.onStartShippingLabelCountdown.bind(this));
        let nextStepMessage = (
            <Message icon info>
                <Icon name={"print"} />
                <Message.Content>
                    <Message.Header>Ready to print the label!</Message.Header>
                    {nextStepButton}
                </Message.Content>
            </Message>
        );

        if (this.state.instantLabelPrinting) {
            let instaPrintMessage = null;
            if (this.state.isLabelPrintTimerActive) {
                instaPrintMessage = (
                    <Transition visible={this.state.labelTimerSeconds <= 2} animation='bounce' duration={1000}>
                        <Message icon warning>
                            <Icon name='circle notched' loading />
                            <Message.Content>
                                <Message.Header>Generating shipping label in {this.state.labelTimerSeconds.toFixed(0)} seconds...</Message.Header>
                            </Message.Content>
                        </Message>
                    </Transition>
                );
            } else {
                instaPrintMessage = nextStepMessage;
            }

            return (
                <>
                    <Header as='h2'>{this.state.bigShipment.inventoryItemIds.length} of {this.state.bigShipment.inventorySlots.length} Items Scanned</Header>
                    {this.state.bigShipment.inventoryItemIds.length === this.state.bigShipment.inventorySlots.length ?
                        instaPrintMessage :
                        <HandScannerInput type="inventory" onScanFinished={this.onScanSerialNumberPicking.bind(this)} />
                    }
                    <BigShipmentInventoryCards
                        schemas={this.state.schemas}
                        bigShipment={this.state.bigShipment}
                        bigOrder={this.state.bigOrder}
                        inventoryItems={this.state.inventoryItems}
                        pickingHints={this.state.pickingHints}
                        onAddAccessoryInventoryItem={this.onAddAccessoryInventoryItem.bind(this)}
                    />
                </>
            );
        } else {
            return (
                <>
                    <Header as='h2'>{this.state.bigShipment.inventoryItemIds.length} of {this.state.bigShipment.inventorySlots.length} Items Scanned</Header>
                    {this.state.bigShipment.inventoryItemIds.length === this.state.bigShipment.inventorySlots.length ?
                        nextStepMessage :
                        <HandScannerInput type="inventory" onScanFinished={this.onScanSerialNumberPicking.bind(this)} />
                    }
                    <BigShipmentInventoryCards
                        schemas={this.state.schemas}
                        bigShipment={this.state.bigShipment}
                        bigOrder={this.state.bigOrder}
                        inventoryItems={this.state.inventoryItems}
                        pickingHints={this.state.pickingHints}
                        onAddAccessoryInventoryItem={this.onAddAccessoryInventoryItem.bind(this)}
                    />
                </>
            );
        }
    }

    startLabelPrintTimer() {
        this.timer = setInterval(this.nextLabelTimerTick.bind(this), 1000);
    }

    nextLabelTimerTick() {
        if (this.state.isLabelPrintTimerActive && this.state.labelTimerSeconds > 0) {
            this.setState({ labelTimerSeconds: this.state.labelTimerSeconds - 1 });
        } else if (this.state.labelTimerSeconds === 0) {
            this.setState({ isLabelPrintTimerActive: false, showPickingCompleteDialog: true });
            clearInterval(this.timer);
        }
    }

    renderPickingCompleteDialog() {
        return (
            <Modal closeOnEscape={true} closeOnDimmerClick={true} closeIcon
                onClose={() => this.setState({ showPickingCompleteDialog: false })}
                open={this.state.showPickingCompleteDialog}>
                <Header icon='shipping' content='Picking Complete!' />
                <Modal.Content>
                    <ol>
                        <li>Place the newly printed shipping label into the picking container.</li>
                        <li>Move the picking container to the packing queue.</li>
                    </ol>
                </Modal.Content>
                <Modal.Actions>
                    <Button color='teal' size='large' loading={this.state.loading} href="/shipper/next">
                        <Icon name='search' />DONE, GET ME THE NEXT ORDER
                    </Button>
                    <Button color='green' size='large' loading={this.state.loading} onClick={this.onStartPacking.bind(this)}>
                        <Icon name='checkmark' />START PACKING
                    </Button>
                </Modal.Actions>
            </Modal>
        )
    }

    onExpandInfo = (e, titleProps) => {
        const { index } = titleProps
        const { infoActiveIndex } = this.state
        const newIndex = infoActiveIndex === index ? -1 : index

        this.setState({ infoActiveIndex: newIndex })
    }

    renderShippingLabel() {
        if (this.state.bigShipment && this.state.bigShipment.currentShippingLabel) {
            let shippingLabel = this.state.bigShipment.currentShippingLabel;

            const nextStepButton = this.renderNextStepButton("Next: Start Packing", this.onStartPacking.bind(this));

            return (
                <>
                    <Header as="h2">Print Shipping Label</Header>

                    {nextStepButton}

                    {this.state.isLabelPrintTimerActive && <Message icon>
                        <Icon name='circle notched' loading />
                        <Message.Header>Printing Label in {this.state.labelTimerSeconds} seconds...</Message.Header>
                    </Message>}

                    {this.renderPickingCompleteDialog()}

                    <BigShipmentLabel autoPrint={true} bigShipment={this.state.bigShipment} />

                    {nextStepButton}
                </>
            );
        } else {
            const nextStepButton = this.renderNextStepButton("Next: Generate Shipping Label", this.onGenerateShippingLabel.bind(this));

            return (
                <>
                    <Header as="h2">Generate Shipping Label</Header>
                    {nextStepButton}
                </>
            );
        }
    }

    renderShippingRateButton() {
        return (
            <Button onClick={this.onCalculateShippingRates.bind(this)}>Calculate Shipping Rates</Button>
        );
    }

    renderShippingRates() {
        if (this.state.shippingRates) {
            return (
                <>
                    {this.state.shippingRates.rates.map((shippingRate, shippingRateIndex) => {
                        return (
                            <Segment>
                                <Header as='h2'>{shippingRate.provider} {shippingRate.servicelevel && shippingRate.servicelevel.name}</Header>
                                <Image src={shippingRate.provider_image_75} />
                                <Header as="h3">{shippingRate.duration_terms}</Header>
                                <Statistic.Group floated="right">
                                    <Statistic>
                                        <Statistic.Value>{shippingRate.amount}</Statistic.Value>
                                        <Statistic.Label>{shippingRate.currency}</Statistic.Label>
                                    </Statistic>
                                </Statistic.Group>
                                <Button onClick={this.onSelectShippingRate.bind(this, shippingRate)}>Select {shippingRate.provider} {shippingRate.servicelevel && shippingRate.servicelevel.name}</Button>
                            </Segment>
                        );
                    })}
                </>
            );
        }
    }

    async onScanShippingLabel(scannedTrackingNumber) {
        this.setState({ loading: true, scannedTrackingNumber: "" });
        try {
            console.log(scannedTrackingNumber);
            const res = await superagent.get(`/api/admin/shipper/shipments?trackingNumber=${_.toUpper(scannedTrackingNumber)}`);
            if (res.body.items.length > 0 && res.body.items[0].id === this.state.bigShipment.id) {
                this.setState({ packingLabelScanned: true });
                /*const res2 = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                    .send({
                        action: "ScanLabelTrackingNumber",
                        scannedTrackingNumber
                    });
                    */
                const audio = new Audio("/misc/Notification3_2.wav");
                audio.play();
            } else {
                this.setState({ error: "Couldn't find label" });
                const audio = new Audio("/misc/Error1.wav");
                audio.play();
            }
        } catch (e) {
            const audio = new Audio("/misc/Error1.wav");
            audio.play();
            this.setState({ error: e });
            console.log(e);
        }
        this.setState({ loading: false });
    }

    async onPackingFinished() {
        const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
            .send({
                action: "FinishPacking"
            });
        await this.reload();
    }

    renderPackingStage() {
        return (
            <>
                <Header as='h2'>1. Scan the shipping label</Header>
                {this.state.packingLabelScanned && this.renderNextStepButton("Yes, I have completed packing the items", this.onPackingFinished.bind(this))}
                <HandScannerInput type="trackingLabel" onScanFinished={this.onScanShippingLabel.bind(this)} />
                <Header as='h2'>2. Pack Items</Header>
                <InventoryItemsTable schemas={this.state.schemas} inventoryItems={this.state.inventoryItems} />
                {this.state.packingLabelScanned && this.renderNextStepButton("Yes, I have completed packing the items", this.onPackingFinished.bind(this))}
            </>
        );
    }

    async onScanFinalShippingLabel(scannedTrackingNumber) {
        this.setState({ loading: true, scannedTrackingNumber: "" });
        try {
            const res = await superagent.get(`/api/admin/shipper/shipments?trackingNumber=${_.toUpper(scannedTrackingNumber)}`);
            if (res.body.items.length > 0 && res.body.items[0].id === this.state.bigShipment.id) {
                this.setState({ packingLabelScanned2: true });
                const audio = new Audio("/misc/Notification3_2.wav");
                audio.play();
            } else {
                this.setState({ error: "Couldn't find label" });
                const audio = new Audio("/misc/Error1.wav");
                audio.play();
            }
        } catch (e) {
            const audio = new Audio("/misc/Error1.wav");
            audio.play();
            this.setState({ error: e });
            console.log(e);
        }
        this.setState({ loading: false });
    }

    async onRegenerateShippingLabel() {
        const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
            .send({
                action: "RegenerateShippingLabel"
            });
        await this.reload();
    }

    async onForceStatusUpdate() {
        const res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
            .send({
                action: "ForceWaitingForPickup"
            });
        await this.reload();
    }

    async onScanSerialNumberRemachineCushion(scannedSerialNumber) {
        if (scannedSerialNumber.startsWith("bs")) {
            scannedSerialNumber = scannedSerialNumber.toUpperCase();
        }

        const res = await superagent.get(`/api/admin/inventory/items?serialNumber=${scannedSerialNumber}`);
        if (res.body.items.length === 1) {
            this.setState({ loading: true, remachinedCushionInventoryItem: res.body.items[0] });
        }

        this.setState({ loading: false });
    }

    async onConfirmRemachineCushion() {
        if (this.state.remachinedCushionInventoryItem) {
            // Remachine the cushion item
            this.setState({ loading: true, error: null });
            let res = await superagent.put(`/api/admin/shipper/shipment/${this.state.bigShipment.id}`)
                .send({
                    inventoryItemId: this.state.remachinedCushionInventoryItem.id,
                    action: "RemachineCushion"
                });

            this.setState({ bigShipment: res.body.shipment, loading: false, remachinedCushionInventoryItem: null });
        }
    }

    renderShippingStage() {
        if (this.state.packingLabelScanned2 === true) {
            return (
                <div>
                    <Header as='h2'>🎉🎉🎉🎉🎉🎉🎉🎉🎉</Header>
                    <Header as='h2'>Shipment is now ready for fulfillment</Header>
                </div>
            );
        } else {
            return (
                <div>
                    <Header as='h2'>Final step! Scan the shipping label on the box to move to fulfillment</Header>
                    <HandScannerInput onScanFinished={this.onScanFinalShippingLabel.bind(this)} />
                </div>
            );
        }
    }

    renderWaitingForPickup() {
        return (
            <Header as='h2'>Waiting for pickup</Header>
        );
    }

    renderSteps() {
        const steps = [
            {
                status: "Picking",
                icon: "find",
                title: "Picking",
                description: "Collect items from inventory"
            },
            {
                status: "PrepareShippingLabel",
                icon: "print",
                title: "Print Shipping Label",
                description: "Print Shipping Label"
            },
            {
                status: "Packing",
                icon: "box",
                title: "Packing",
                description: "Pack items and seal"
            },
            {
                status: "PreparingToShip",
                icon: "truck",
                title: "Preparing To Ship",
                description: "Final check"
            },
            {
                status: "WaitingForPickup",
                icon: "box",
                title: "Waiting For Pickup",
                description: "Waiting for pickup from carrier"
            }
        ];

        const uiSteps = [];

        for (let i = 0; i < steps.length; i++) {
            let step = steps[i];
            let active = this.state.bigShipment.status === step.status;
            // Completed if the index of status less than the current step index
            let completed = _.findIndex(steps, (s) => s.status === this.state.bigShipment.status) > i;
            let disabled = _.findIndex(steps, (s) => s.status === this.state.bigShipment.status) < i;

            uiSteps.push(
                <Step active={active} completed={completed} disabled={disabled}>
                    <Step.Content>
                        <Step.Title>{step.title}</Step.Title>
                        <Step.Description>{step.description}</Step.Description>
                    </Step.Content>
                </Step>
            );
        }

        return (
            <Step.Group ordered>
                {uiSteps}
            </Step.Group>
        );
    }

    render() {
        if (this.state.bigShipment) {
            const shipmentHistory = (
                <Table compact celled padded>
                    <Table.Header>
                        <Table.Row>
                            <Table.HeaderCell width={2}>When</Table.HeaderCell>
                            <Table.HeaderCell width={2}>User</Table.HeaderCell>
                            <Table.HeaderCell fluid>Message</Table.HeaderCell>
                        </Table.Row>
                    </Table.Header>
                    <Table.Body>
                        {this.state.bigShipment.history.map((historyItem, historyItemIndex) => {
                            let createdAtDateTime = fromUnixTime(historyItem.createdAt / 1000);
                            const createdAt = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
                            return (<Table.Row>
                                <Table.Cell width={2}>
                                    {createdAt}
                                </Table.Cell>
                                <Table.Cell width={2}>
                                    {historyItem.creatorBigscreenAccountId}
                                </Table.Cell>
                                <Table.Cell>
                                    {historyItem.message}
                                    {(historyItem.metaData && historyItem.metaData.reason) && <div><strong>Reason:</strong> {historyItem.metaData.reason}</div>}
                                </Table.Cell>
                            </Table.Row>)
                        })}
                    </Table.Body>
                </Table>
            );

            let createdAtDateTime = fromUnixTime(this.state.bigShipment.createdAt / 1000);
            const createdAt = formatInTimeZone(createdAtDateTime, DEFAULT_TIMEZONE, 'PPPp z');
            const fromNow = formatDistanceToNow(createdAtDateTime, { addSuffix: true });

            const title = (
                <div style={{ display: "flex", marginBottom: "1em" }}>
                    <div style={{ flex: 1 }}>
                        <Header as="h2">
                            {`🚢 Shipment ${this.state.bigShipment.id}`}
                        </Header>
                        <p>Created: {createdAt} ({fromNow})</p>
                    </div>
                </div>
            );

            let body;
            if (this.state.bigShipmentError) {
                body = <BigApiErrorMessage error={this.state.bigShipmentError} />;
            } else {
                body = (
                    <>
                        {this.renderSteps()}
                        <BigApiErrorMessage error={this.state.error} />
                        <Segment raised padded>
                            {this.state.bigShipment.status === "Picking" && this.renderPickingStage()}
                            {this.state.bigShipment.status === "PrepareShippingLabel" && this.renderShippingLabel()}
                            {this.state.bigShipment.status === "Packing" && this.renderPackingStage()}
                            {this.state.bigShipment.status === "PreparingToShip" && this.renderShippingStage()}
                            {this.state.bigShipment.status === "WaitingForPickup" && this.renderWaitingForPickup()}
                        </Segment>
                    </>
                );
            }

            return (
                <>
                    {this.renderCancelShipmentModal()}

                    <BigShipperWrapper loading={this.state.loading}>
                        {title}
                        {this.renderTestStatus()}
                        {this.renderShipmentStatus()}

                        <Accordion fluid styled defaultActiveIndex={0}>
                            <Accordion.Title active={true} index={0} onClick={this.onExpandInfo}>
                                <Icon name='dropdown' />
                                For Order: 📦 <span style={{ textDecoration: "underline" }}>{this.state.bigOrder.shopifyOrderName}</span>
                            </Accordion.Title>
                            <Accordion.Content active={this.state.infoActiveIndex === 0}>
                                <Table celled>
                                    <BigOrderComponent allowClicks={false} asTableRow={true} schemas={this.state.schemas} bigOrder={this.state.bigOrder} showDetail={false} />
                                </Table>
                            </Accordion.Content>

                            <Accordion.Title active={true} index={1} onClick={this.onExpandInfo} >
                                <Icon name='dropdown' />
                                Items ({this.state.bigShipment.inventoryItemIds.length})
                            </Accordion.Title>
                            <Accordion.Content active={this.state.infoActiveIndex === 1}>
                                <InventoryItemsTable schemas={this.state.schemas} inventoryItems={this.state.inventoryItems} />
                            </Accordion.Content>

                            <Accordion.Title active={true} index={2} onClick={this.onExpandInfo} >
                                <Icon name='dropdown' />
                                Shipment History ({this.state.bigShipment.history.length} events)
                            </Accordion.Title>
                            <Accordion.Content active={this.state.infoActiveIndex === 2}>
                                {shipmentHistory}
                            </Accordion.Content>

                            {this.state.bigShipment.currentShippingLabel && <Accordion.Title active={true} index={3} onClick={this.onExpandInfo} >
                                <Icon name='dropdown' />
                                Shipping Label
                            </Accordion.Title>
                            }
                            {this.state.bigShipment.currentShippingLabel && <Accordion.Content active={this.state.infoActiveIndex === 3}>
                                <ApiButtonModal color="orange" size="small" text="Regenerate Shipping Label ($$$)" cancel modalIcon="redo" icon="redo" modalButtonText="OK, regenerate the shipping label" onConfirm={this.onRegenerateShippingLabel.bind(this)}>
                                    Are you sure you want to regenerate this shipping label?  A new label will cost us money!
                                    <br /><br /><strong>Note: </strong>For now, the previous shipping label will not automatically be cancelled - please destroy in Shippo.
                                </ApiButtonModal>
                                <BigShipmentLabel autoPrint={false} bigShipment={this.state.bigShipment} />
                            </Accordion.Content>}
                        </Accordion>
                        {body}

                        <Segment color="red">
                            <Header as="h2" color="red">Danger Zone</Header>
                            <Table compact celled definition>
                                <Table.Body>
                                    {(this.state.bigShipment.inventorySlots.find(item => ["CustomCushion", "BeyondCushionV1"].includes(item.productType))) && <Table.Row>
                                        <Table.HeaderCell width={4}>Re-machine Cushion</Table.HeaderCell>
                                        <Table.Cell>
                                            <ApiButtonModal color="blue" size="small" text="Re-machine Cushion" modalIcon="cogs" icon="cogs" modalButtonText="Yes, re-machine this cushion"
                                                onShowModal={(async () => { this.setState({ remachinedCushionInventoryItem: null }); }).bind(this)}
                                                onConfirm={this.onConfirmRemachineCushion.bind(this)}>
                                                {(this.state.remachinedCushionInventoryItem)
                                                    ? <p>
                                                        <Segment color="green" inverted>Found!</Segment>
                                                        Re-machining cushion for inventory item: <strong>{this.state.remachinedCushionInventoryItem.serialNumber}</strong>
                                                    </p>
                                                    : <HandScannerInput type="inventory" onScanFinished={this.onScanSerialNumberRemachineCushion.bind(this)} />
                                                }
                                                This will force the cushion to be re-machined with a priority of 99.
                                            </ApiButtonModal>
                                        </Table.Cell>
                                    </Table.Row>}
                                    {(this.state.bigShipment.status === "Packing" || this.state.bigShipment.status === "PreparingToShip") && <Table.Row>
                                        <Table.HeaderCell width={4}>Force Status Update</Table.HeaderCell>
                                        <Table.Cell>
                                            <ApiButtonModal color="orange" size="small" text="Force Waiting For Pickup" modalIcon="bus" icon="bus" modalButtonText="Yes, force update the shipment status" onConfirm={this.onForceStatusUpdate.bind(this)}>
                                                This force updates the shipment status to "Waiting For Pickup" - use with caution!
                                                <br /><br />This will only work if the underlying items in the shopify order(s) have all been fulfilled.
                                            </ApiButtonModal>
                                        </Table.Cell>
                                    </Table.Row>}
                                    <Table.Row>
                                        <Table.HeaderCell width={4}>Cancel shipment</Table.HeaderCell>
                                        <Table.Cell>
                                            <Button color="red" onClick={() => this.setState({ showCancelShipmentModal: true })} size="small">Cancel Shipment</Button>
                                        </Table.Cell>
                                    </Table.Row>
                                </Table.Body>
                            </Table>
                        </Segment>
                    </BigShipperWrapper>
                </>
            );
        } else {
            return null;
        }
    }
}
