import React, { useEffect, useRef, useState } from 'react'
import { createPortal } from 'react-dom'
import moment from 'moment'
import { UStoreProvider } from '@ustore/core'
import { createUEdit } from '@ustore/uedit'
import { useClickOutside } from '$themehooks'

import UEditProvider from './ueditProvider'
import UEditMainControlsPanel from './UEditMainControlsPanel'
import { Paginator } from '../../Paginatior'

import theme from '$styles/_theme.scss'
import '@ustore/uedit/dist/style.css'
import './UEdit.scss'
import './UEditNoSelection.scss'

let currentCustomizationValues = {}

const UEditProduct = ({
  isControlsOpen,
  product,
  onElementClicked,
  properties,
  uEditAdvancedMode,
  orderItem,
  setUeditSelectedBoxId,
  setUEditLocks,
  isMobile
}) => {
  const [, setSelectedPage] = useState(0)
  const [hasSelection, setHasSelection] = useState(false)
  const ueditContainerRef = useRef()
  const [viewerState, setViewerState] = useState({})
  const [initialScale, setInitialScale] = useState(1)
  const [documentHasMultiplePages, setDocumentHasMultiplePages] = useState(false)

  const onSelection = () => {
    UEditProvider.clearSavedTextSelection()
    const isSelected = UEditProvider.uEdit.getSelection().length > 0
    if (UEditProvider?.uEdit?.getSelection()[0]) {
      setUeditSelectedBoxId(UEditProvider?.uEdit?.getSelection()[0]?.id)
      UEditProvider.setLocks()
      setUEditLocks(UEditProvider.locks)
    }
    setHasSelection(isSelected)

    onElementClicked && onElementClicked(isSelected)
  }
  const clearSelection = (e) => {
    if (!e.target.closest('.button') && e.target.closest('.left')) {
      e.stopPropagation()
      UEditProvider.clearSelection()
    }
  }
  const onDocumentLoaded = () => {
    window.queueMicrotask(onResizeWindow)
    UEditProvider.fitToPage()
    setDocumentHasMultiplePages(UEditProvider.getPageCount() > 1)
    setViewerState({
      pageNumber: UEditProvider.uEdit.getPageInView() + 1,
      totalPageNumber: UEditProvider.getPageCount()
    })
    setInitialScale(UEditProvider.uEdit.zoom())
  }
  const onEnterPage = (e, inPageInView) => setSelectedPage(inPageInView)

  const onResizeWindow = () => onResize(ueditContainerRef)
  useClickOutside(ueditContainerRef, clearSelection, true)

  useEffect(() => {
    if (orderItem?.DocumentUrl) {
      const newDocumentUrl = orderItem.DocumentUrl
      const loadUEdit = async (stop) => {
        if (!stop) {
          return
        }
        if (!ueditContainerRef.current && !UEditProvider.uEdit) {
          window.queueMicrotask(() => loadUEdit(stop - 1))
          return
        }
        UEditProvider.uEdit = createUEdit(ueditContainerRef.current, {
          width: '100%',
          height: '100%',
          showProgressOnRead: false,
          resizeDefaultProportional: false,
          resizeDefaultScale: true,
          openMode: 'FlatDesign',
          uEditPICssClass: 'uedit-main-container-flat-design',
          uEditMarginClass: 'UEdit-document-margin-flat-design'
        })
        UEditProvider.element = ueditContainerRef.current
        UEditProvider.setViewMode('preview')

        UEditProvider.registerEvent('documentLoaded.UEdit.data-api', onDocumentLoaded)
        UEditProvider.registerEvent('enterPage.uEditStoreView.xmpie', onEnterPage)
        UEditProvider.registerEvent('itemSelected.uEditStoreView.xmpie', onSelection)
        await UEditProvider.loadAssets(product)
        await UEditProvider.loadDocument(newDocumentUrl)

      }
      loadUEdit(10)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [orderItem])

  useEffect(() => {
    if (!UEditProvider?.uEdit) {
      return
    }
    if (!properties) return;

    (async () => {
      const customizationValues = Object.keys(properties).length === 0 ? [] :
        Object.values(properties).filter(prop => prop.custom?.affectProof).map((property) => ({
            ID: property.custom.id,
            Value: property.uiSchema['ui:widget'] === 'dateTimePicker' ? createDateObject(property.value, property) : property.value || '',
          })
        )

      UEditProvider.allowedAdors = Object.values(properties)
        .filter(prop => prop.custom?.affectProof)
        .reduce((r, { custom, uiSchema }) => ({ ...r, [custom?.code]: uiSchema['ui:widget'] }), {})

      if (areCustomizationValuesEqua(customizationValues, currentCustomizationValues) && Object.keys(properties).length !== 0) {
        return
      }

      currentCustomizationValues = customizationValues
      const proofSetData = await UStoreProvider.api.products.generateProofSet(orderItem.ID, customizationValues)

      UEditProvider.uEdit && refetchProofSet(orderItem, proofSetData, UEditProvider, UEditProvider.uEdit.zoom())

    })()
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [properties])

  useEffect(() => {
    window.addEventListener('resize', onResizeWindow, true)
    onResizeWindow()
    return () => {
      UEditProvider.unregisterEvent('documentLoaded.UEdit.data-api', onDocumentLoaded)
      UEditProvider.unregisterEvent('enterPage.uEditStoreView.xmpie', onEnterPage)
      UEditProvider.unregisterEvent('itemSelected.uEditStoreView.xmpie', onSelection)
      UEditProvider.dispose()
      currentCustomizationValues = {}
      window.removeEventListener('resize', onResizeWindow)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  const setPage = (newPage) => {
    const currentPage = UEditProvider.uEdit.getPageInView() + 1
    const { totalPageNumber } = viewerState
    const documentView = UEditProvider.uEdit.getDocumentView()
    if (newPage !== currentPage && newPage > 0 && newPage <= totalPageNumber) {
      const pageDifference = newPage - currentPage
      const navigationMethod = pageDifference > 0
        ? documentView.goToNextPage
        : documentView.goToPreviousPage
      for (let i = 0; i < Math.abs(pageDifference); i++) {
        navigationMethod.call(documentView)
      }
      setViewerState({ ...viewerState, pageNumber: newPage })
      UEditProvider.uEdit.zoom(initialScale)
      onResizeWindow(ueditContainerRef)
    }
  }

  return <div className="uedit-wrapper">
    {UEditProvider.element &&
      <UEditMainControlsPanel hasSelection={hasSelection} uEditAdvancedMode={uEditAdvancedMode}/>}
    <div className="uedit-editor-preview">
      <div id="uEditDesktop">
        <div id="uEditControl" ref={ueditContainerRef} data-controls-open={`${isControlsOpen}`}/>
      </div>
    </div>

    {documentHasMultiplePages && createPortal(<Paginator
      viewerState={viewerState}
      setPage={setPage}
    />, document.querySelector(isMobile ? '.mobile-product' : '.uedit-wrapper'))}

  </div>
}

export default UEditProduct

function refetchProofSet (orderItem, proofSetData, ueditProvider, initialScale) {
  if (ueditProvider.uEdit) {
    UStoreProvider.api.products.getProofSet(orderItem.ID, proofSetData?.ProofSetID).then((checkProofSetData) => {
      if (checkProofSetData?.Data) {
        const handler = () => {
          ueditProvider.uEdit?.getUndoService().clear()
          ueditProvider.unregisterEvent('documentReady.uEditStoreView.xmpie', handler)
        }
        ueditProvider.registerEvent('documentReady.uEditStoreView.xmpie', handler)
        ueditProvider.pushAdorValues(checkProofSetData?.Data)
        ueditProvider.uEdit?.zoom(initialScale)
      } else {
        if (checkProofSetData?.Status === 1) {
          setTimeout(() => refetchProofSet(orderItem, proofSetData, ueditProvider, initialScale), 1000)
        }
      }
    })
  }
}

function createDateObject (str, property) {
  const mDate = moment(str, true)
  const timeZone = Intl.DateTimeFormat().resolvedOptions().timeZone

  return {
    date: str ? mDate.format('YYYY-MM-DD') : '',
    time: property.uiSchema['ui:options'].custom.timePickerParams ? mDate.format('HH:mm') : '',
    timeZone
  }
}

function onResize (ueditContainerRef) {
  if (!ueditContainerRef?.current) {
    return
  }
  const isMobileBreakpoint = document.body.clientWidth < parseInt(theme.md.replace('px', ''))
  const uEditResize = () => {
      const container = document.getElementById('uEditControl')
      container.style.width = '100%'
      const height = isMobileBreakpoint ? container.parentElement.offsetHeight : container.parentElement.parentElement.offsetHeight
      container.style.height = `${height}px`
      UEditProvider.fitToPage()
  }

  const ueditElement = ueditContainerRef.current
  if (ueditElement) {
    if (isMobileBreakpoint) {
      const mobileContainer = document.getElementById('uEditMobile')
      if (ueditElement.parentElement !== mobileContainer && mobileContainer) {
        mobileContainer.appendChild(ueditElement)
      }
    } else {
      const desktopContainer = document.getElementById('uEditDesktop')
      if (ueditElement.parentElement !== desktopContainer && desktopContainer) {
        desktopContainer.appendChild(ueditElement)
      }
    }
    uEditResize()
  }
}

function areCustomizationValuesEqua (a, b) {
  const aMap = a.reduce((r, { ID, Value }) => ({ ...r, [ID]: Value }), {})
  return a.length === b.length && b.every(({ ID, Value }) => aMap[ID] === Value)
}
