import './StaticProduct.scss'
import React, {Component} from 'react'
import {throttle} from 'throttle-debounce'
import ProductLayout from '../product/ProductLayout'
import ProductDetails from '../product/ProductDetails'
import ImageCarousel from '../carousel/ImageCarousel'
import ProductOrderSummary from '../product/ProductOrderSummary'
import ProductPropertiesNG from '../product/ProductPropertiesNG'
import ProductDeliveryMethod from '../product/ProductDeliveryMethod'
import {UStoreProvider} from '@ustore/core'
import {isOutOfStock} from '../Inventory'
import LoadingDots from '$core-components/LoadingDots'
import {Popover, PopoverBody} from 'reactstrap'
import {ReactComponent as ErrorIcon} from "$assets/icons/error.svg"
import Price from '../Price'
import themeContext from '$ustoreinternal/services/themeContext'
import {ReactComponent as ProofIcon} from "$assets/icons/proof.svg"
import ProductProof from "../product/ProductProof"
import ProductStickyPrice from "../product/ProductStickyPrice"
import ProductApproval from "../product/ProductApproval"
import {t} from '$themelocalization'
import urlGenerator from '$ustoreinternal/services/urlGenerator'
import {Router} from '$routes'
import {decodeStringForURL, isServer} from '$ustoreinternal/services/utils'
import theme from '$styles/_theme.scss'
import _ from 'lodash'
import {
  convertProductPropertiesFormIntoArray,
  PriceNotUpdatedReason, shouldPriceBeUpdatedByUpdates,
  shouldPriceBeUpdatedDespiteErrors,
  checkIfUploadedFileIsProof
} from "../../services/utils";

const EXCEL_PRICING_ATTRIBUTE_NAME = 'PartialPriceCalculationEnabled'

export class StaticProduct extends Component {

  constructor(props) {
    super(props)

    this.orderProduct = {}
    this.initialDataLoaded = false
    this.firstPriceCalculated = false
    this.firstPropertiesValidationPassed = false
    this.ducErrors = []

    this.state = {
      isLoading: (props.currentProduct && props.currentProduct.Configuration.Properties && props.currentProduct.Configuration.Properties.length),
      proofApproved: false,
      activeCarouselSlide: 0,
      activeModalCarouselSlide: 0,
      isPriceCalculating: false,
      isQuantityValid: true,
      isPriceValid: true,
      showErrorPopover: false,
      errorPopoverText: t('product.validation_error'),
      errorPopoverTarget: null,
      errorPopoverPlacement: 'top',
      selectedDelivery: null,
      isPreviewModalOpen: false,
      isApprovalModalOpen: false,
      doValidateIframe: false,
      isLoadingReorder: false,
      isValidOnFirstAddToCart: true,
      showPriceWarningPopover: false,
      priceWarningPopoverTarget: '.price-wrapper',
      priceWarningPopoverPlacement: 'top',
      affectPricePropertiesValid: true,
      allPropertiesValid: true,
      isAddClicked: false
    }

    this.promiseResolve = null
    this.promiseReject = null
    this.updatePricePromiseIdentifier = null
  }

  oniFrameClick = () => {
    if (document.activeElement.closest('iframe')) {
      this.setState({ showErrorPopover: false })
    }
  }

  isFirstPriceCalculated = async () => {
    const { customState: { currentProduct, currentOrderItemId, currentOrderItemPriceModel } } = this.props

    if (!this.initialDataLoaded && currentProduct) {
      this.initialDataLoaded = true
      await this.getData(currentProduct.ID, currentOrderItemId)
    }
    if (currentOrderItemPriceModel && currentOrderItemPriceModel.Price && !this.firstPriceCalculated) {
      this.firstPriceCalculated = true

      await this.onCalculatePrice(true)
    }
  }

  componentDidMount () {
    window.addEventListener('scroll', this.onScroll, true)
    window.addEventListener('beforeunload', this.doDataCleanup, true);
    window.addEventListener('blur', this.oniFrameClick, true);

    this.onScroll()
    this.isFirstPriceCalculated()
      .then(res => res)
      .catch(err => err)
  }

  doDataCleanup = () => {
    UStoreProvider.state.customState.delete('currentProduct')
    UStoreProvider.state.customState.delete('currentOrderItem')
    UStoreProvider.state.customState.delete('currentOrderItemId')
    UStoreProvider.state.customState.delete('currentOrderItemPriceModel')
    UStoreProvider.state.customState.delete('lastOrder')
    UStoreProvider.state.customState.delete('currentProductThumbnails')
    UStoreProvider.state.customState.delete('currentDeliveryServices')
    UStoreProvider.state.customState.delete('CurrentProductDucErrors')
    UStoreProvider.state.customState.delete('ducData')
    UStoreProvider.state.customState.delete('currentProductProperties')
    UStoreProvider.state.customState.delete('isLoadingData')
  }

  componentWillUnmount() {
    this.doDataCleanup()
    window.removeEventListener('scroll', this.onScroll, true)
    window.removeEventListener('blur', this.oniFrameClick, true);
    window.removeEventListener('beforeunload', this.doDataCleanup, true);
  }

  getData = async function (productID, orderItemID) {
    if (!productID) return

    UStoreProvider.state.customState.set({ isLoadingData: true })

    const product = await UStoreProvider.api.products.getProductByID(productID)
    const thumbnails = await UStoreProvider.api.products.getProductThumbnails(productID)

    let orderProduct
    if (orderItemID) {
      orderProduct = await UStoreProvider.api.orders.getOrderItem(orderItemID)
    } else {
      orderProduct = await UStoreProvider.api.orders.addOrderItem(productID)
    }
    this.orderProduct = orderProduct
    const lastOrder = await UStoreProvider.api.orders.getLastOrder(productID) //null

    let deliveryServices = null
    if (product.Configuration.Delivery.Mailing.Enabled) {
      deliveryServices = await UStoreProvider.api.orders.getDeliveryServices(orderProduct.ID)    }
    else {
      deliveryServices = {}
    }

    let properties = await UStoreProvider.api.orders.getProperties(orderProduct.ID)

    Object.keys(properties.formData).forEach((key) => {
      if (properties.formData[key] === "" || properties.formData[key] === '[]') {
        properties.formData[key] = undefined
      }

      if (properties.UISchema[key]['ui:widget'] === 'fileUpload') {
        properties.JSONSchema.definitions[key] = {
          ...properties.JSONSchema.definitions[key],
          pattern: '[\\w+\\d+\_$&+,:;=?@#|\'<>.^*()%!-]+\\.\\w+|^|[^\x00-\x7F]+$',
          custom: {
            ...properties.JSONSchema.definitions[key].custom,
            maskErrors: ['pattern']
          }
        }

        properties.UISchema[key] = {
          ...properties.UISchema[key],
          ['ui:errorMessages']: {
            ...properties.UISchema[key]['ui:errorMessages'],
            pattern: "Please wait for files to be uploaded"
          }
        }
      }
    })

    orderProduct && UStoreProvider.api.orders.getPriceOrderItem(orderProduct.ID, orderProduct).then((res) => {
      UStoreProvider.state.customState.set('currentOrderItemPriceModel', res)
    })

    if (product.Proof) {
      UStoreProvider.state.customState.set('currentProduct', {
        ...product,
        Proof: {
          ...product.Proof,
          MimeType: checkIfUploadedFileIsProof(properties) ? 'application/pdf' : product.Proof.MimeType
        }
      })
    } else {
      UStoreProvider.state.customState.set('currentProduct', {
        ...product,
      })
    }

    UStoreProvider.state.customState.setBulk({
      currentProductThumbnails: thumbnails,
      currentOrderItem: orderProduct,
      lastOrder: lastOrder,
      currentDeliveryServices: deliveryServices,
      isLoadingData: false,
      currentProductProperties: properties
    })
  }

  componentDidUpdate(prevProps, prevState) {
    const { isPriceCalculating } = this.state
    const { isPriceCalculating: prevIsPriceCalculating } = prevState

    if (prevIsPriceCalculating && !isPriceCalculating) {
      this.onScroll()
    }

    if (_.isEqual(this.props.customState, prevProps.customState) && !this.initialDataLoaded) {
      const {customState} = this.props
      const {currentProduct, currentOrderItemId} = customState

      if (!this.initialDataLoaded && currentProduct) {
        this.initialDataLoaded = true
        this.getData(currentProduct.ID, currentOrderItemId)
          .then((res) => res)
          .catch((err) => err)
      }
    }
  }

  isExcelPricingEnabled = () => {
    const { customState: { currentProduct }} = this.props

    return currentProduct.Attributes.find((attr) => {
      return attr.Name === EXCEL_PRICING_ATTRIBUTE_NAME
    }).Value === 'true'
  }

  isInViewport = (el, top = 159) => {
    const rect = el.getBoundingClientRect();
    return (
      rect.top >= top && // header height + tooltip height
      rect.left >= 0 &&
      rect.bottom - rect.height <= (window.innerHeight || document.documentElement.clientHeight) &&
      rect.right <= (window.innerWidth || document.documentElement.clientWidth)
    );
  }

  onScroll = throttle(250, false,() => {
    const stickyPanel = document.querySelector('.sticky-price')
    const topMarker = document.querySelector('.static-product-price')
    const header = document.querySelector('.header')
    const bottomMarker = document.querySelector('.add-to-cart-button')

    const headerHeight = header ? header.getBoundingClientRect().height : 0

    if (stickyPanel && bottomMarker) {
      if ((topMarker && topMarker.getBoundingClientRect().top + topMarker.getBoundingClientRect().height >= headerHeight)
        || bottomMarker.getBoundingClientRect().top <= window.innerHeight) {
        stickyPanel.style.height = '0'
        stickyPanel.style.padding = '0'
      } else {
        stickyPanel.style.height = 'auto'
        stickyPanel.style.padding = '7.5px 0'
        stickyPanel.style.boxShadow = '0 -2px 16px var(--color-line)'
        stickyPanel.style.transition = 'all .3s ease'
      }
    }

    // hide the error popover when scrolling the target out of view.
    if (this.state.showErrorPopover && this.state.errorPopoverTarget) {
      const element = document.querySelector(this.state.errorPopoverTarget)
      const isInSticky = element.closest('.sticky-price')
      const isInView = this.isInViewport(element)
      const isStickyHidden = stickyPanel.style.height === '0px'

      if ((!isInSticky && !isStickyHidden) || (isInSticky && isStickyHidden)) this.setState({ showErrorPopover: false })
      else if (!isInView) { this.setState({ showErrorPopover: false }) }
    }

    if (this.state.showPriceWarningPopover) {
      const element = document.querySelector(this.state.priceWarningPopoverTarget)
      const isInView = this.isInViewport(element, 80)

      if (!isInView) {
        this.setState({ showPriceWarningPopover: false })
      }
    }
  })

  // A method to calculate the price of this kit OrderItem.
  // The price is calculated with the API and change the price model in the state in order to re render all children.
  // Optional parameter:
  //    - updatedKitOrderItem - an updated kit OrderItem to perform calculation of price according to, if doesnt exist takes the currentOrderItem from the props
  onCalculatePrice = throttle(750, async (firstTimeCalculating = false) => {
    const { customState: { currentOrderItem, currentDeliveryServices, currentProduct, currentProductProperties } } = this.props
    const { isLoading, isQuantityValid } = this.state
    if (!isQuantityValid || isLoading || !currentOrderItem || !currentDeliveryServices) return

    this.setState({ isPriceCalculating: true, showPriceWarningPopover: false })

    if (currentProduct.Configuration &&
      currentProduct.Configuration.Delivery &&
      currentProduct.Configuration.Delivery.Shipping.Enabled === false &&
      currentProduct.Configuration.Delivery.Mailing.Enabled === true &&
      currentOrderItem.DeliveryMethod === 1) {
      currentOrderItem.DeliveryMethod = 2
      currentOrderItem.DeliveryServiceID = currentDeliveryServices.MailingServices[0].ID
    }

    const currentUpdatePricePromiseIdentifier = Date.now()
    this.updatePricePromiseIdentifier = currentUpdatePricePromiseIdentifier

    UStoreProvider.api.orders.getPriceOrderItem(currentOrderItem.ID, {
      ...currentOrderItem,
      Properties: convertProductPropertiesFormIntoArray(currentProductProperties, this.isExcelPricingEnabled())
    }).then((priceModel) => {
      if (this.updatePricePromiseIdentifier !== currentUpdatePricePromiseIdentifier) {
        return
      }

      this.setState({ isPriceCalculating: false })
      const isPriceValid = priceModel.Price && priceModel.Price.Price !== -1
      if (!isPriceValid && !firstTimeCalculating) {
        const { selector, placement } = this.getPriceErrorPopoverTarget()
        this.state.affectPricePropertiesValid
          ? this.setState({
              showErrorPopover: true,
              errorPopoverTarget: selector,
              errorPopoverPlacement: placement,
              errorPopoverText: t('product.price_is_not_valid')
            })
          : this.setState({
            showPriceWarningPopover: true,
            priceWarningPopoverTarget: selector,
            priceWarningPopoverPlacement: placement
          })
      }

      //validating that the returned price is the one received from the last updated OrderItem object, otherwise discard it.
      if (isPriceValid || firstTimeCalculating) {
        UStoreProvider.state.customState.set('currentOrderItemPriceModel', priceModel)
      }
      this.setState({ isPriceValid })
    })
  })

  onQuantityChange = (value, isValid, initialChange) => {
    const { customState: { currentOrderItem, currentProduct, currentOrderItemPriceModel } } = this.props
    const { affectPricePropertiesValid, allPropertiesValid } = this.state

    const hasProperties = currentProduct.Configuration.Properties && currentProduct.Configuration.Properties.length > 0
    const shouldOrderItemBeUpdated = () => {
      if (!hasProperties) {
        return isValid
      } else if (!this.isExcelPricingEnabled()) {
        return !initialChange && isValid && affectPricePropertiesValid
      } else {
        return !initialChange && isValid
      }
    }
    const { selector, placement } = this.getPriceErrorPopoverTarget()

    !affectPricePropertiesValid
      ? this.setState({
        showPriceWarningPopover: true,
        priceWarningPopoverTarget: selector,
        priceWarningPopoverPlacement: placement,
        tempQuantity: value
      }) :
      this.setState({
          tempQuantity: value,
          isQuantityValid: isValid
      }, async () => shouldOrderItemBeUpdated && this.saveOrderItem())

    if (shouldOrderItemBeUpdated()) {
      currentOrderItem.Quantity = value

      UStoreProvider.state.customState.set('currentOrderItem', currentOrderItem)
      currentOrderItemPriceModel && currentOrderItemPriceModel.Price && this.onCalculatePrice()
    }
  }

  onPropertiesClearValidation = (orderItemID) => {
    this.setState({ doValidateIframe: false })
  }

  onPropertiesStatusChanged = (orderItemID, isValid) => {
    isValid ? this.promiseResolve() : this.promiseReject()
  }

  validateAndSave = async (errorPopoverTarget) => {
    const { customState: { currentProduct, currentProductProperties, currentOrderItem, currentOrderItemPriceModel } } = this.props

    this.setState({ isLoading: true, showErrorPopover: false })

    const { isQuantityValid, selectedDelivery, isPriceValid, allPropertiesValid } = this.state

    const ngValid = isQuantityValid && (selectedDelivery
      || (!currentProduct.Configuration.Delivery.Mailing.Enabled
        && !currentProduct.Configuration.Delivery.Shipping.Enabled))

    if(currentOrderItemPriceModel && currentOrderItemPriceModel.Price && (!allPropertiesValid || !ngValid || !isPriceValid)) {
      this.setState({ isLoading: false, showErrorPopover: true, errorPopoverTarget })
      return false
    }

    await UStoreProvider.api.orders.updateProperties(
      currentOrderItem.ID,
      convertProductPropertiesFormIntoArray(currentProductProperties, this.isExcelPricingEnabled())
    )
    // TODO - right now its not need
    // start the iframe validation process by setting the doValidateIframe flag to true which will trigger validation request to the iframe.
    // if (currentProduct && currentProduct.Configuration.Properties && currentProduct.Configuration.Properties.length) {
    //   this.setState({ doValidateIframe: true })
    //
    //   // create a promise that would be resolved or rejected when iframe returns valid\invalid.
    //   try {
    //     await new Promise((resolve, reject) => {
    //       this.promiseResolve = resolve;
    //       this.promiseReject = reject;
    //     });
    //   } catch (error) {
    //     this.setState({ isLoading: false, showErrorPopover: true, errorPopoverTarget })
    //
    //     return false
    //   }
    // }

    await this.saveOrderItem()

    this.setState({ isLoading: false })

    return true
  }

  onPropertiesLoadComplete = (orderItemID) => {
    this.setState({ isLoading: false })
  }

  onContinueClick = async (errorPopoverTarget) => {
    if (this.state.isLoading) return
    const { customState: { currentProduct, currentOrderItemPriceModel } } = this.props
    const { allPropertiesValid } = this.state

    const staticProductElement = document.querySelector(`.static-product`)
    staticProductElement.classList.add('ignore-mask-error')

    this.setState({
      isAddClicked: true
    }, async () => {
      await this.validateAndSave(errorPopoverTarget)

      if(!allPropertiesValid) {
        this.setState({isValidOnFirstAddToCart: false })
        return
      }

      if (!(await this.validateAndSave(errorPopoverTarget))) return

      if (currentProduct.Configuration.Proof && currentProduct.Configuration.Proof.RequireProofApproval) {
        if(currentOrderItemPriceModel && currentOrderItemPriceModel.Price) {
          this.onCalculatePrice()
        }
        this.toggleApprovalModal()
        return
      }

      await this.addToCartOrSave()
      // validation will be done on NG, and if passed, then on iFrame and if that passed as well, saving will happen.
    })
  }

  saveOrderItem = async () => {
    const { customState: { currentOrderItem, currentProductProperties, currentProduct } } = this.props
    const { Configuration: { Quantity } } = currentProduct

    currentOrderItem.Quantity = this.state.tempQuantity ? this.state.tempQuantity : currentOrderItem.Quantity

    const currentQuantity = currentOrderItem.Quantity
    const { Minimum, Maximum } = Quantity
    const isOutOfRange = currentQuantity && ((Minimum && currentQuantity < Minimum) || (Maximum && currentQuantity > Maximum))

    if (!isOutOfRange) {
      // call the update order api
      await UStoreProvider.api.orders.updateOrderItem(currentOrderItem.ID, {
        ...currentOrderItem,
        Properties: convertProductPropertiesFormIntoArray(currentProductProperties, this.isExcelPricingEnabled())
      })
    }

  }

  addToCartOrSave = async () => {
    const { customState: { currentProduct } } = this.props

    if (this.getIsOutOfStock(currentProduct))
      await this.saveForLater()
    else
      await this.addToCart()
  }

  addToCart = async () => {
    const { customState: { currentOrderItem } } = this.props

    // call the add to cart api and route to cart if succeeds.
    await UStoreProvider.api.orders.addToCart(currentOrderItem.ID)

    this.routeToCart()
  }

  saveForLater = async () => {
    const { customState: { currentOrderItem } } = this.props

    // call the add to cart api and route to cart if succeeds.
    await UStoreProvider.api.orders.saveForLater(currentOrderItem.ID)

    this.routeToCart()
  }

  routeToCart = () => {
    const { state: { currentStore: { StoreType } }, customState: { currentOrderItem } } = this.props
    const { cartUrl } = themeContext.get()

    // handle connectNG store:
    if (StoreType === 3 && cartUrl) {
      const decoded = decodeURIComponent(cartUrl)
      window.location.href = `${decoded}${decoded.includes('?') ? '&' : '?'}OrderProductId=${currentOrderItem.FriendlyID}`
    }
    else {
      Router.pushRoute(urlGenerator.get({ page: 'cart' }))
    }
  }

  getPriceErrorPopoverTarget = (placement = 'top', selector = '#add-to-cart-button') => {
    const stickyPanel = document.querySelector('.sticky-price')
    if (stickyPanel && stickyPanel.style.height !== '0px') {
      placement = 'top'
      selector = '.product-sticky-price .total-price'
    }

    const mainPriceElement = document.querySelector('#total-price-component .price-display')
    if (mainPriceElement && this.isInViewport(mainPriceElement)) {
      placement = 'bottom'
      selector = '#total-price-component .price-display'
    }

    const summaryTablePriceElement = document.querySelector('.summary-table .total-row .price-display')
    if (summaryTablePriceElement && this.isInViewport(summaryTablePriceElement)) {
      placement = 'top'
      selector = '.summary-table .total-row .price-display'
    }

    return { placement, selector }
  }

  toggleErrorPopover = (errorPopoverTarget = '', errorPopoverPlacement = 'top', errorPopoverText = t('product.validation_error')) => {
    this.setState({
      showErrorPopover: !this.state.showErrorPopover,
      errorPopoverTarget,
      errorPopoverPlacement,
      errorPopoverText
    })
  }

  togglePriceWarningPopover = (priceWarningPopoverPlacement = 'bottom') => {
    this.setState({ showPriceWarningPopover: !this.state.showPriceWarningPopover, priceWarningPopoverPlacement })
  }

  onDeliveryChanged = (value, serviceID = null, initialChange = false) => {
    const { customState: { currentOrderItem, currentProduct, currentOrderItemPriceModel } } = this.props

    currentOrderItem.DeliveryMethod = value
    currentOrderItem.DeliveryServiceID = serviceID

    UStoreProvider.state.customState.set('currentOrderItem', currentOrderItem)

    this.setState({ selectedDelivery: value }, () => {
      !initialChange && currentOrderItemPriceModel && currentOrderItemPriceModel.Price && this.onCalculatePrice()
    })
  }

  toggleProofModal = () => {
    this.setState({ isPreviewModalOpen: !this.state.isPreviewModalOpen })
  }

  toggleApprovalModal = () => {
    this.setState({ isApprovalModalOpen: !this.state.isApprovalModalOpen })
  }

  getMinQuantity = (currentProduct) => {
    return currentProduct.Configuration &&
      currentProduct.Configuration.Quantity &&
      currentProduct.Configuration.Quantity.Minimum ? currentProduct.Configuration.Quantity.Minimum : 0
  }

  getIsOutOfStock = (currentProduct) => {
    const minQuantity = this.getMinQuantity(currentProduct)

    return currentProduct.Inventory
      && isOutOfStock(currentProduct.Inventory
      && currentProduct.Inventory.Quantity, minQuantity, currentProduct.Inventory
      && currentProduct.Inventory.AllowOutOfStockPurchase)
  }

  onReorder = async () => {
    const { customState: { currentProduct, lastOrder } } = this.props
    this.setState({ isLoading: true, isLoadingReorder: true })
    const newOrder = await UStoreProvider.api.orders.reorder(lastOrder.OrderItemID)
    const newURL = `${urlGenerator.get({ page: 'products', id: currentProduct.FriendlyID, name: decodeStringForURL(currentProduct.Name) })}?OrderItemId=${newOrder.ID}&reorder=true`
    window.location.replace(newURL)
  }

  handleIframeMessages = (e) => {
    const { customState: { currentOrderItem } } = this.props

    if (!currentOrderItem) return

    // almost all messages are handled inside the generic iFrameHelper.
    // since this message is only for static product, then we dont want to handle it in the generic helper.]
    if (e.data.type === '@PRODUCTION_OUTPUT_HAS_VALUE') {
      const msgOrderItemID = e.data.data.orderItemID
      if (msgOrderItemID && msgOrderItemID === currentOrderItem.ID) {
        // this message means that we need to hide the view proof link.
        this.setState({ hideProofLinkFromIframe: true })
      }
    }
  }

  onFormChange = (newFormData, prevFormData, errors = [], visibleErrors = [], newSchema) => {
    const { customState: { currentProductProperties: { JSONSchema }, currentOrderItemPriceModel}} = this.props

    errors = errors.length > 0 && errors.reduce((acc, next) => {
    const key = next.dataPath.replaceAll(/['"\[\]]+/g, '')
      acc = acc.concat({
        ...next,
        affectPrice: JSONSchema.definitions[key].custom.affectPrice
      })
      return acc
    }, [])

    this.setState({
      isAddClicked: false
    })

    if(!newFormData.errorFromServer) {
      const { result: errorsDontAffectPrice, error } = shouldPriceBeUpdatedDespiteErrors(errors, visibleErrors, this.isExcelPricingEnabled())
      const { result: updatesAffectPrice } = shouldPriceBeUpdatedByUpdates(newFormData, prevFormData, newSchema || JSONSchema)
      const { selector, placement } = this.getPriceErrorPopoverTarget()
      this.setState({
        allPropertiesValid: (!errors || errors.length === 0) && (!visibleErrors || visibleErrors.length === 0),
        affectPricePropertiesValid: (!errors || errors.findIndex(i => i.affectPrice) === -1) && (!visibleErrors || visibleErrors.findIndex(i => i.affectPrice) === -1),
        showPriceWarningPopover: this.firstPropertiesValidationPassed && updatesAffectPrice && error === PriceNotUpdatedReason.hiddenError,
        priceWarningPopoverTarget: selector,
        priceWarningPopoverPlacement: placement
      })
      this.firstPropertiesValidationPassed = true

      if (updatesAffectPrice && errorsDontAffectPrice) {
        if(currentOrderItemPriceModel && currentOrderItemPriceModel.Price) { this.onCalculatePrice()}
      }
    } else {
      if(newFormData.errorFromServer
        && newFormData.errorFromServer.ErrorCode
        && newFormData.errorFromServer.ErrorCode === "ExcelCalculation") {
        const priceModel = {
          ...currentOrderItemPriceModel.Price,
          Price: -1
        }
        this.setState({
          errorPopoverPlacement: 'bottom',
          showErrorPopover: true,
          errorPopoverTarget: '#total-price-component .price-display',
          errorPopoverText: t('product.price_is_not_valid'),
          allPropertiesValid: false
        })

        UStoreProvider.state.customState.set('currentOrderItemPriceModel', {...currentOrderItemPriceModel, Price: priceModel})
      }
    }
  }

  render() {
    const { customState } = this.props
    const { currentProduct, currentOrderItem, isLoadingData } = customState

    if (!customState || !customState.currentProduct ||
      isLoadingData || isServer() || !this.initialDataLoaded) {
      return null
    }

    if (!this.initialDataLoaded && !currentProduct) {
      return null
    }

    const {
      customState: {
        currentOrderItemPriceModel,
        currentProductThumbnails,
        lastOrder,
        currentDeliveryServices,
        currentProductProperties
      },
      state:
      { currentStore:
        { TaxFormatType },
        currentCurrency
      }
    } = this.props

    if (!currentOrderItem || !currentDeliveryServices) {
      return null
    }

    const { languageCode } = themeContext.get()

    const minQuantity = this.getMinQuantity(currentProduct)
    const isProductOutOfStock = this.getIsOutOfStock(currentProduct)
    const addOrSaveText = isProductOutOfStock ? t('product.save_for_later') : t('product.add_to_cart')
    const continueButtonText = currentProduct.Configuration.Proof && currentProduct.Configuration.Proof.RequireProofApproval ? t('product.review_approve') : addOrSaveText
    const { router: { asPath } } = this.props

    const showReorderLink = !asPath.includes('reorder')
    const hasProperties = currentProduct.Configuration.Properties && currentProduct.Configuration.Properties.length > 0

    const showPricing = currentProduct && currentOrderItemPriceModel && currentOrderItemPriceModel.Price !== null
    const priceComponent = currentOrderItemPriceModel !== undefined && showPricing
      ? (
        <div className='static-product-price'>
          <div className='total-price' id='total-price-component'>
            {this.state.isPriceCalculating || !currentOrderItemPriceModel || currentOrderItemPriceModel === undefined
              ? <LoadingDots />
              : <div className='price-wrapper'>
                <Price model={currentOrderItemPriceModel.Price}
                  showCurrency
                  isMinimumPrice={currentOrderItemPriceModel.IsMinimumPrice} />

              </div>
            }
          </div>
        </div>
      ) : null

    const getViewProofComponent = (currentProduct, isMobile, hasThumbnails = true, orderItemID) => {
      if (!currentProduct || !currentProduct.Proof) return null

      if (this.state.hideProofLinkFromIframe) return null

      const fileURL = `${currentProduct.Proof.Url}&OrderItemID=${orderItemID}`

      // if mobile && not image OR desktop and not image and not PDF -> download instead of modal
      const isDownloadProof = currentProduct.Proof &&
        ((isMobile && !currentProduct.Proof.MimeType.startsWith('image/')) ||
          (!isMobile && currentProduct.Proof.MimeType !== "application/pdf" &&
            !currentProduct.Proof.MimeType.startsWith('image/')))

      if (!isMobile) {
        if (isDownloadProof) {
          return <a download className="view-proof-wrapper desktop" href={fileURL} >
            <div className="view-proof">
              <ProofIcon className="view-proof-icon" width="20px" height="24px" />
              <div className="view-proof-title">{t('product.view_proof')}</div>
            </div>
          </a >
        }

        return < div className="view-proof-wrapper desktop" onClick={this.toggleProofModal} >
          <div className="view-proof">
            <ProofIcon className="view-proof-icon" width="20px" height="24px" />
            <div className="view-proof-title">{t('product.view_proof')}</div>
          </div>
        </div >
      }
      else {
        // mobile
        if (isDownloadProof) {
          return <a download className={`view-proof-wrapper mobile ${hasThumbnails ? '' : 'no-thumbs'}`} href={fileURL}>
            <ProofIcon className="view-proof-icon" width="20px" height="24px" />
          </a>
        }
        return <div className={`view-proof-wrapper mobile ${hasThumbnails ? '' : 'no-thumbs'}`} onClick={this.toggleProofModal}>
          <ProofIcon className="view-proof-icon" width="20px" height="24px" />
        </div>
      }
    }
    const isMobile = document.body.clientWidth < parseInt(theme.md.replace('px', ''))
    const proofURL = currentProduct.Proof ? `${currentProduct.Proof.Url}&OrderItemID=${currentOrderItem.ID}` : null

    return (<ProductLayout className='static-product'>
      <left is="custom">
        <ImageCarousel
          showTitle={true}
          scale={0.8}
          activeSlide={this.state.activeCarouselSlide}
          images={currentProductThumbnails.Thumbnails}
          onChange={this.onCarouselImageChange}
        />
        {
          getViewProofComponent(currentProduct, false, true, currentOrderItem.ID)
        }
      </left>
      <right is="custom">
        {this.state.isLoadingReorder &&
        <div className='loading-content-container'>
          <LoadingDots/>
        </div>
        }
        <ProductDetails
          className='static-product'
          productModel={currentProduct}
          minimumQuantity={minQuantity}
          reorderModel={showReorderLink ? lastOrder : null}
          onReorder={this.onReorder}
          showInStock={true}
          langCode={languageCode}
        />
        {isMobile && <div className='image-carousel-mobile'>
          <ImageCarousel
            zoomAllowed={false}
            activeSlide={this.state.activeCarouselSlide}
            images={currentProductThumbnails.Thumbnails}
            onChange={() => {
            }}
          />
          {
            getViewProofComponent(currentProduct, true, currentProductThumbnails && currentProductThumbnails.Thumbnails.length > 1)
          }
        </div>}
        {priceComponent}
        <div className='static-product-wizard'>
          <ProductPropertiesNG
            className='static-product-properties'
            productModel={currentProduct}
            isAddClicked={this.state.isAddClicked}
            orderModel={currentOrderItem}
            orderProduct={this.orderProduct}
            propertiesModel={currentProductProperties}
            onQuantityChange={this.onQuantityChange}
            onStatusChanged={this.onPropertiesStatusChanged}
            onLoadComplete={this.onPropertiesLoadComplete}
            onCalculatePrice={this.onCalculatePrice}
            isPriceCalculating={this.state.isPriceCalculating}
            clearValidateActionFlag={this.onPropertiesClearValidation}
            onFormChange={this.onFormChange}
            onFirstValidate={this.onFormChange}
            excelPricingEnabled={this.isExcelPricingEnabled()}
            onFirstAddToCart={this.state.isValidOnFirstAddToCart}
            translations={t}
          />
        </div>
        <ProductDeliveryMethod
          className='static-delivery-method'
          productModel={currentProduct}
          onDeliveryChange={this.onDeliveryChanged}
          currentDeliveryMethod={currentOrderItem ? currentOrderItem.DeliveryMethod : null}
          currentDeliveryServiceID={currentOrderItem ? currentOrderItem.DeliveryServiceID : null}
          deliveryServices={currentDeliveryServices ? currentDeliveryServices : null}
        />
        <ProductOrderSummary
          currency={currentCurrency.Code}
          deliveryMethod={this.state.selectedDelivery}
          className='static-order-summary'
          productModel={currentProduct}
          quantity={currentOrderItem.Quantity}
          taxFormatType={TaxFormatType}
          priceModel={currentOrderItemPriceModel}
          isPriceCalculating={this.state.isPriceCalculating}
        />
        <ProductProof
          onAddToCartClick={this.onContinueClick}
          isModalOpen={this.state.isPreviewModalOpen}
          modalClassName="static-product-proof-modal"
          src={proofURL}
          type={currentProduct.Proof && currentProduct.Proof.MimeType ? currentProduct.Proof.MimeType : ''}
          onCloseModal={this.toggleProofModal}
          isMobile={isMobile}/>
        <ProductApproval
          isModalOpen={this.state.isApprovalModalOpen}
          src={proofURL}
          type={currentProduct.Proof && currentProduct.Proof.MimeType ? currentProduct.Proof.MimeType : ''}
          onCloseModal={this.toggleApprovalModal}
          onAddToCartClick={this.addToCartOrSave}
          addToCartBtnText={addOrSaveText}
          checkboxText={currentProduct.Configuration && currentProduct.Configuration.Proof && currentProduct.Configuration.Proof.ProofApprovalText}
          errorText={currentProduct.Configuration && currentProduct.Configuration.Proof && currentProduct.Configuration.Proof.ProofApprovalValidationMessage}
        />
        <div
          id="add-to-cart-button"
          className='button button-primary add-to-cart-button'
          onClick={this.onContinueClick.bind(this, '#add-to-cart-button')}
        >
          {this.state.isLoading || this.state.isPriceCalculating ? <LoadingDots/> : continueButtonText}
        </div>
      </right>
    <sticky className='hidden' is="custom">
      {
        this.state.showErrorPopover &&
        <Popover
          placement={this.state.errorPopoverPlacement}
          isOpen={this.state.showErrorPopover}
          target={document.querySelector(this.state.errorPopoverTarget ? this.state.errorPopoverTarget : '#add-to-cart-button')}
          toggle={this.toggleErrorPopover}
          className="error-popover"
        >
          <PopoverBody>
            <div className='popover-close'>
              {/* <div className='close-btn' onClick={this.toggleErrorPopover}>×</div> */}
            </div>
            <ErrorIcon className='error-icon' width='15px' height='15px'/>
            <div className='popover-message'>
              {this.state.errorPopoverText}
            </div>
          </PopoverBody>
        </Popover>
      }
      {
        this.state.showPriceWarningPopover &&
        <Popover
          placement={this.state.priceWarningPopoverPlacement}
          isOpen={this.state.showPriceWarningPopover}
          target={document.querySelector(this.state.priceWarningPopoverTarget)}
          toggle={this.togglePriceWarningPopover}
          className='grey-price-popover'
        >
          <PopoverBody>
            <div className='popover-message'>
              {t('product.price_cannot_be_updated')}
            </div>
          </PopoverBody>
        </Popover>
      }
      <ProductStickyPrice
        longPrice={TaxFormatType === 3}
        disabled={this.state.isLoading || this.state.isPriceCalculating}
        onClick={this.onContinueClick}
        addToCartBtnText={continueButtonText}
        priceModel={currentOrderItemPriceModel}
        isPriceLoading={this.state.isLoading || this.state.isPriceCalculating}
      />
    </sticky>
  </ProductLayout>);
  }
}

export default StaticProduct
