import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
import { useSelector } from 'react-redux'
import config from 'config'
import reduce from 'lodash/reduce'

import When from '@komi-app/when'
import { Preview, ProgressActivity } from '@komi-app/creator-ui'

import { useModules } from 'hooks/useModules'
import { selectActiveModule } from 'redux/Talent/selector'
import { selectTalentProfileModules, selectUserData } from 'redux/User/selector'
import { IframeMessage } from 'utils/iframeMessage'

import { SHOPIFY_MODULE_TYPE } from '../../../constants/shopify'
import { selectShopifyStores } from '../../../redux/Shopify/selector'

import './ProfilePreviewDrawer.scss'
import classNames from 'classnames'
import { useBodyScrollLock } from '../../../utils/useBodyScrollLock'
import { useCurrentProfilePreviewUrl } from '../../../hooks/useCurrentProfilePreviewUrl'
import { FLAGS, useFeatureIsOn } from '@komi-app/flags-sdk'

import { ModuleType } from '@komi-app/shared-types'

const CONSUMER_URL = config.client.url
const TALENT_PREVIEW_URL = CONSUMER_URL + '/talent-profile-preview'

function ProfilePreviewDrawer() {
  const iframeRef = useSyncProfilePreviewIframe()
  const isProfilePreviewUrlDomainFixEnabled = useFeatureIsOn(
    FLAGS.FIX_SB_869_PREVIEW_NOT_PLAYING_VIDEOS
  )
  const profilePreviewUrl = useCurrentProfilePreviewUrl()

  const [iframeLoaded, setIframeLoaded] = useState<boolean>(false)
  const [drawerExpanded, setDrawerExpanded] = useState<boolean>(false)
  const debouncedDrawerExpanded = useDebouncedState(drawerExpanded, 500)

  const { lock, unlock } = useBodyScrollLock()

  useEffect(() => {
    if (drawerExpanded) {
      lock()
    } else {
      unlock()
    }
  }, [drawerExpanded, lock, unlock])

  return (
    <div
      className={classNames('profile-preview-drawer-wrapper', {
        'profile-preview-drawer-expanded':
          drawerExpanded || debouncedDrawerExpanded
      })}
    >
      <Preview
        isExpanded={drawerExpanded}
        onOpen={() => setDrawerExpanded(true)}
        onClose={() => setDrawerExpanded(false)}
      >
        <When
          value={!iframeLoaded}
          then={
            <div className="profile-preview-drawer-loader">
              <ProgressActivity fill="white" />
            </div>
          }
        />
        <iframe
          style={{
            display: iframeLoaded ? 'block' : 'none'
          }}
          className="profile-preview-drawer-iframe"
          ref={iframeRef}
          src={
            isProfilePreviewUrlDomainFixEnabled
              ? profilePreviewUrl
              : TALENT_PREVIEW_URL
          }
          onLoad={() => {
            setIframeLoaded(true)
          }}
        />
      </Preview>
    </div>
  )
}

function useDebouncedState(watchedValue: boolean, timeout: number) {
  const [debouncedValue, setDebouncedValue] = useState<boolean>(false)

  useEffect(() => {
    const timer = setTimeout(() => {
      setDebouncedValue(watchedValue)
    }, timeout)
    return () => clearTimeout(timer)
  }, [watchedValue])

  return debouncedValue
}

/**
 * This hook is used to sync the current talent profile data (modules, header image etc)
 * to the iframe via window.postMessage().
 */
function useSyncProfilePreviewIframe() {
  const iframeRef = useRef<HTMLIFrameElement | null>(null)
  const user = useSelector(selectUserData)
  const talentProfileModules = useSelector(selectTalentProfileModules)
  const stores = useSelector(selectShopifyStores)
  const activeModule = useSelector(selectActiveModule)

  const { thirdPartyData } = useModules()
  const currentModules = useMemo(() => {
    return reduce(
      talentProfileModules,
      (result: any, item: any) => {
        if (
          [
            ModuleType.SHOP_MY_SHELF,
            ModuleType.SHOP_LIST,
            ModuleType.YOUTUBE_COLLECTION,
            ModuleType.BANDSINTOWN,
            ModuleType.PODCAST_AUTOMATION,
            ModuleType.SEATED
          ].includes(item.type)
        ) {
          const data = thirdPartyData.find((el: any) => el.id === item.id)
          let items
          switch (item.type) {
            case ModuleType.SHOP_MY_SHELF:
            case ModuleType.SHOP_LIST:
              items = data?.products
              break
            case ModuleType.YOUTUBE_COLLECTION:
              items = data?.collection?.items
              break
            case ModuleType.BANDSINTOWN:
              items = data?.events || []
              break
            case ModuleType.SEATED:
              items = data?.events?.shows || []
              break
            case ModuleType.PODCAST_AUTOMATION:
              items = data?.collection?.items || []
              break
            default:
              break
          }
          return [
            ...result,
            {
              ...item,
              items: items || [],
              displayLatest: item.items[0].activeLatestPodcast
            }
          ]
        }
        if (item.type === ModuleType.GROUP) {
          const items = reduce(
            item.items,
            (newItems: any, element: any) => {
              if (
                [
                  ModuleType.SHOP_MY_SHELF,
                  ModuleType.SHOP_LIST,
                  ModuleType.YOUTUBE_COLLECTION,
                  ModuleType.BANDSINTOWN,
                  ModuleType.SEATED,
                  ModuleType.PODCAST_AUTOMATION
                ].includes(element.type as ModuleType)
              ) {
                const data = thirdPartyData.find(
                  (el: any) => el.id === element.id
                )

                let items
                switch (element.type) {
                  case ModuleType.SHOP_MY_SHELF:
                  case ModuleType.SHOP_LIST:
                    items = data?.products
                    break
                  case ModuleType.YOUTUBE_COLLECTION:
                    items = data?.collection?.items
                    break

                  case ModuleType.BANDSINTOWN:
                    items = data?.events || []
                    break
                  case ModuleType.SEATED:
                    items = data?.events?.shows || []
                    break
                  case ModuleType.PODCAST_AUTOMATION:
                    items = data?.collection?.items || []
                    break
                  default:
                    break
                }

                return [
                  ...newItems,
                  {
                    ...element,
                    displayLatest: element.items[0].activeLatestPodcast,
                    items: items || []
                  }
                ]
              }
              return [...newItems, element]
            },
            []
          )

          return [
            ...result,
            {
              ...item,
              items
            }
          ]
        }
        return [...result, item]
      },
      []
    )
  }, [thirdPartyData, talentProfileModules])

  const shopifyMerchants = useMemo(() => {
    return talentProfileModules?.reduce((result: any, item) => {
      if (
        [
          SHOPIFY_MODULE_TYPE.SHOPIFY_COLLECTION,
          SHOPIFY_MODULE_TYPE.SHOPIFY_PRODUCT
        ].includes(item.type)
      ) {
        const storeDomain = (item.items?.[0] as any)?.shop || ''

        const accessToken =
          stores?.find(store => store.domain === storeDomain)?.accessToken ||
          user?.talentProfile?.shopifyMerchants?.[storeDomain]?.accessToken
        result[storeDomain] = accessToken
        return result
      }
      return result
    }, {})
  }, [stores, user, talentProfileModules])

  const handleSendTalentProfile = useCallback(async () => {
    if (!iframeRef) return
    const message = {
      type: 'komi_talent_profile',
      data: {
        ...user,
        talentProfile: {
          ...user?.talentProfile,
          modules: currentModules,
          shopifyMerchants
        }
      }
    }
    iframeRef.current?.contentWindow?.postMessage(JSON.stringify(message), '*')
    IframeMessage.postMessage(message)
  }, [user, currentModules, shopifyMerchants])

  const handleMessage = useCallback(
    async (event: MessageEvent) => {
      const { type } = event.data
      switch (type) {
        case 'komi_consumer_loaded':
          handleSendTalentProfile()
          break
        default:
          break
      }
    },
    [handleSendTalentProfile]
  )

  useEffect(() => {
    IframeMessage.bindEvent(window, 'message', handleMessage)
    return () => {
      IframeMessage.unbindEvent(window, 'message', handleMessage)
    }
  }, [handleMessage])

  useEffect(() => {
    handleSendTalentProfile()
  }, [handleSendTalentProfile])

  useEffect(() => {
    if (!activeModule || !iframeRef) {
      return
    }

    const message = {
      type: 'komi_talent_profile_active_module',
      data: {
        activeModule
      }
    }
    iframeRef.current?.contentWindow?.postMessage(JSON.stringify(message), '*')
    IframeMessage.postMessage(message)
  }, [iframeRef, activeModule])
  return iframeRef
}

export default ProfilePreviewDrawer
