import { Component, useEffect, useState } from 'react'
import PropTypes from 'prop-types'
import { siteConfig } from '@/lib/config'

export default function Messenger() {
  const pageId = siteConfig('FACEBOOK_PAGE_ID')
  const appId = siteConfig('FACEBOOK_APP_ID')
  const language = siteConfig('LANG').replace('-', '_')

  // 新增一个状态变量用于追踪是否已经滚动过
  const [showMessenger, setShowMessenger] = useState(false);

  const showTheComponent = () => {
    window.removeEventListener('scroll', showTheComponent);
    if (!showMessenger) {
      setShowMessenger(true);
    }
  };

  // 延时7秒，或页面滚动时加载该组件
  useEffect(() => {
    window.addEventListener('scroll', showTheComponent);
    setTimeout(() => {
      showTheComponent()
    }, 7000);
    return () => {
      window.removeEventListener('scroll', showTheComponent);
    };
  }, []);

  return <>
        {showMessenger && <MessengerCustomerChat
            pageId={pageId}
            appId={appId}
            language={language}
            shouldShowDialog={true}
        />}
    </>
}

/**
 * @see https://github.com/Yoctol/react-messenger-customer-chat
 */
class MessengerCustomerChat extends Component {
  constructor(props) {
    super(props)
    this.state = {
      fbLoaded: false,
      shouldShowDialog: undefined
    }
  }

  /**
     * 初始化
     */
  componentDidMount() {
    this.setFbAsyncInit()
    this.reloadSDKAsynchronously()
  }

  componentDidUpdate(prevProps) {
    if (
      prevProps.pageId !== this.props.pageId ||
            prevProps.appId !== this.props.appId ||
            prevProps.shouldShowDialog !== this.props.shouldShowDialog ||
            prevProps.htmlRef !== this.props.htmlRef ||
            prevProps.minimized !== this.props.minimized ||
            prevProps.themeColor !== this.props.themeColor ||
            prevProps.loggedInGreeting !== this.props.loggedInGreeting ||
            prevProps.loggedOutGreeting !== this.props.loggedOutGreeting ||
            prevProps.greetingDialogDisplay !== this.props.greetingDialogDisplay ||
            prevProps.greetingDialogDelay !== this.props.greetingDialogDelay ||
            prevProps.autoLogAppEvents !== this.props.autoLogAppEvents ||
            prevProps.xfbml !== this.props.xfbml ||
            prevProps.version !== this.props.version ||
            prevProps.language !== this.props.language
    ) {
      this.setFbAsyncInit()
      this.reloadSDKAsynchronously()
    }
  }

  componentWillUnmount() {
    if (window.FB !== undefined) {
      window.FB.CustomerChat.hide()
    }
  }

  /**
     * 初始化
     */
  setFbAsyncInit() {
    const { appId, autoLogAppEvents, xfbml, version } = this.props

    window.fbAsyncInit = () => {
      window.FB.init({
        appId,
        autoLogAppEvents,
        xfbml,
        version: `v${version}`
      })

      this.setState({ fbLoaded: true })
    }
  }

  loadSDKAsynchronously() {
    const { language } = this.props;
    /* eslint-disable */
        (function (d, s, id) {
            var js,
                fjs = d.getElementsByTagName(s)[0];
            if (d.getElementById(id)) {
                return;
            }
            js = d.createElement(s);
            js.id = id;
            js.src = `https://connect.facebook.net/${language}/sdk/xfbml.customerchat.js`;
            if (fjs && fjs.parentNode && fjs.parentNode.contains(fjs)) {
              fjs.parentNode.insertBefore(js, fjs);
            } else {
              document.body.appendChild(js);
            }
        })(document, 'script', 'facebook-jssdk');
        /* eslint-enable */
  }

  removeFacebookSDK() {
    removeElementByIds(['facebook-jssdk', 'fb-root'])

    delete window.FB
  }

  reloadSDKAsynchronously() {
    this.removeFacebookSDK()
    this.loadSDKAsynchronously()
  }

  controlPlugin() {
    const { shouldShowDialog } = this.props

    if (shouldShowDialog) {
      window.FB.CustomerChat.showDialog()
    } else {
      window.FB.CustomerChat.hideDialog()
    }
  }

  subscribeEvents() {
    const { onCustomerChatDialogShow, onCustomerChatDialogHide } = this.props

    if (onCustomerChatDialogShow) {
      window.FB.Event.subscribe(
        'customerchat.dialogShow',
        onCustomerChatDialogShow
      )
    }

    if (onCustomerChatDialogHide) {
      window.FB.Event.subscribe(
        'customerchat.dialogHide',
        onCustomerChatDialogHide
      )
    }
  }

  createMarkup() {
    const {
      pageId,
      htmlRef,
      minimized,
      themeColor,
      loggedInGreeting,
      loggedOutGreeting,
      greetingDialogDisplay,
      greetingDialogDelay
    } = this.props

    const refAttribute = htmlRef !== undefined ? `ref="${htmlRef}"` : ''
    const minimizedAttribute =
            minimized !== undefined ? `minimized="${minimized}"` : ''
    const themeColorAttribute =
            themeColor !== undefined ? `theme_color="${themeColor}"` : ''
    const loggedInGreetingAttribute =
            loggedInGreeting !== undefined
              ? `logged_in_greeting="${loggedInGreeting}"`
              : ''
    const loggedOutGreetingAttribute =
            loggedOutGreeting !== undefined
              ? `logged_out_greeting="${loggedOutGreeting}"`
              : ''
    const greetingDialogDisplayAttribute =
            greetingDialogDisplay !== undefined
              ? `greeting_dialog_display="${greetingDialogDisplay}"`
              : ''
    const greetingDialogDelayAttribute =
            greetingDialogDelay !== undefined
              ? `greeting_dialog_delay="${greetingDialogDelay}"`
              : ''

    return {
      __html: `<div
        class="fb-customerchat"
        page_id="${pageId}"
        ${refAttribute}
        ${minimizedAttribute}
        ${themeColorAttribute}
        ${loggedInGreetingAttribute}
        ${loggedOutGreetingAttribute}
        ${greetingDialogDisplayAttribute}
        ${greetingDialogDelayAttribute}
      ></div>`
    }
  }

  render() {
    const { fbLoaded, shouldShowDialog } = this.state

    if (fbLoaded && shouldShowDialog !== this.props.shouldShowDialog) {
      document.addEventListener(
        'DOMNodeInserted',
        (event) => {
          const element = event.target
          if (
            element.className &&
                        typeof element.className === 'string' &&
                        element.className.includes('fb_dialog')
          ) {
            this.controlPlugin()
          }
        },
        false
      )
      this.subscribeEvents()
    }
    // Add a random key to rerender. Reference:
    // https://stackoverflow.com/questions/30242530/dangerouslysetinnerhtml-doesnt-update-during-render
    return <div key={Date()} dangerouslySetInnerHTML={this.createMarkup()} />
  }
}

const removeElementByIds = (ids) => {
  ids.forEach((id) => {
    const element = document.getElementById(id)
    if (element && element.parentNode) {
      element.parentNode.removeChild(element)
    }
  })
}

MessengerCustomerChat.propTypes = {
  pageId: PropTypes.string.isRequired,
  appId: PropTypes.string,
  shouldShowDialog: PropTypes.bool,
  htmlRef: PropTypes.string,
  minimized: PropTypes.bool,
  themeColor: PropTypes.string,
  loggedInGreeting: PropTypes.string,
  loggedOutGreeting: PropTypes.string,
  greetingDialogDisplay: PropTypes.oneOf(['show', 'hide', 'fade']),
  greetingDialogDelay: PropTypes.number,
  autoLogAppEvents: PropTypes.bool,
  xfbml: PropTypes.bool,
  version: PropTypes.string,
  language: PropTypes.string,
  onCustomerChatDialogShow: PropTypes.func,
  onCustomerChatDialogHide: PropTypes.func
}

MessengerCustomerChat.defaultProps = {
  appId: null,
  shouldShowDialog: false,
  htmlRef: undefined,
  minimized: undefined,
  themeColor: undefined,
  loggedInGreeting: undefined,
  loggedOutGreeting: undefined,
  greetingDialogDisplay: undefined,
  greetingDialogDelay: undefined,
  autoLogAppEvents: true,
  xfbml: true,
  version: '11.0',
  language: 'en_US',
  onCustomerChatDialogShow: undefined,
  onCustomerChatDialogHide: undefined
}
