/* eslint-disable complexity */
import { INPUT, isFacebook, isInstagram, isWhatsapp } from '@botonic/core'
import React, { useContext } from 'react'

import { RequestContext } from '../../contexts'
import { WhatsappButtonList, WhatsappCTAUrlButton } from '..'
import { Reply } from '../reply'
import { Text } from '../text'
import { MultichannelFacebook } from './facebook/facebook'
import { MultichannelButton } from './multichannel-button'
import { MultichannelContext } from './multichannel-context'
import {
  buttonTypes,
  elementHasPostback,
  elementHasUrl,
  elementHasWebview,
  getButtonType,
  getMultichannelButtons,
  getMultichannelReplies,
  isNodeButton,
} from './multichannel-utils'
import {
  DEFAULT_WHATSAPP_MAX_BUTTON_SEPARATOR,
  MENU_BUTTON_WHATSAPP_BUTTON_LIST,
  MULTICHANNEL_WHATSAPP_PROPS,
  WHATSAPP_LIST_MAX_BUTTONS,
  WHATSAPP_MAX_BUTTONS,
} from './whatsapp/constants'
import { convertToMarkdownMeta } from './whatsapp/markdown-meta'

export const MultichannelText = props => {
  const requestContext = useContext(RequestContext)
  const multichannelContext = useContext(MultichannelContext)
  const postbackButtonsAsText = props.buttonsAsText ?? true

  let elements = []

  const getText = children => {
    children = Array.isArray(children) ? children : [children]
    const text = children
      .filter(e => e && !e.type)
      .map(e => {
        if (Array.isArray(e)) {
          return getText(e)
        } else {
          return String(e)
        }
      })
      .join('')
    if (text === undefined) {
      return []
    }
    return [text].filter(t => t !== '') // to avoid line breaks when the carousel doesn't have title or subtitle
  }

  const getButtonsAndReplies = () =>
    [].concat(
      getMultichannelButtons(React.Children.toArray(props.children)),
      getMultichannelReplies(React.Children.toArray(props.children))
    )

  const getWhatsappButtons = () => {
    const postbackButtons = []
    const urlButtons = []
    const webviewButtons = []
    for (const button of getButtonsAndReplies()) {
      if (elementHasUrl(button)) {
        urlButtons.push(button)
      } else if (elementHasWebview(button)) {
        webviewButtons.push(button)
      } else if (elementHasPostback(button)) {
        postbackButtons.push(button)
      }
    }
    return { postbackButtons, urlButtons, webviewButtons }
  }

  const getDefaultIndex = () => {
    if (props.indexMode === undefined) {
      return undefined
    }
    if (multichannelContext.currentIndex != null) {
      return multichannelContext.currentIndex
    }
    return props.indexMode === 'letter' ? 'a' : 1
  }

  const regenerateMultichannelButtons = (newLineFirstButton = true) => {
    const generator = (multichannelButton, i) => {
      const type = getButtonType(multichannelButton)
      const asText =
        type === buttonTypes.POSTBACK ? postbackButtonsAsText : true
      const newline =
        multichannelContext.messageSeparator == null &&
        !newLineFirstButton &&
        i === 0
          ? ''
          : '\n'

      return (
        <MultichannelButton
          key={`${type}${i}`}
          newline={newline}
          asText={asText}
          {...multichannelButton.props}
        >
          {multichannelButton.props.children}
        </MultichannelButton>
      )
    }
    return generator
  }

  const splitInWhatsappListButtons = postbackButtons => {
    const messages = []
    for (
      let i = 0;
      i < postbackButtons.length;
      i += WHATSAPP_LIST_MAX_BUTTONS
    ) {
      messages.push(postbackButtons.slice(i, i + WHATSAPP_LIST_MAX_BUTTONS))
    }
    return messages
  }

  if (isWhatsapp(requestContext.session)) {
    const texts = getText(props.children)
    const { postbackButtons, urlButtons, webviewButtons } = getWhatsappButtons()

    const textElements = texts.map(text => {
      const textWithMarkdown = convertToMarkdownMeta(text)
      return (props.newline || '') + textWithMarkdown
    })

    const webviewButtonElements = webviewButtons.map(
      regenerateMultichannelButtons(false)
    )

    const buttonsTextSeparator =
      props.buttonsTextSeparator || DEFAULT_WHATSAPP_MAX_BUTTON_SEPARATOR

    const exceedWhatsAppMaxButtonNumber =
      !postbackButtonsAsText && postbackButtons.length > WHATSAPP_MAX_BUTTONS

    if (exceedWhatsAppMaxButtonNumber) {
      const menuButtonTextWhatsappList =
        props.menuButtonTextWhatsappList || MENU_BUTTON_WHATSAPP_BUTTON_LIST

      const urlButtonElements = urlButtons.map(
        regenerateMultichannelButtons(!!texts.length)
      )
      const postbackButtonElements = postbackButtons.map(
        regenerateMultichannelButtons(!!texts.length || !!urlButtons.length)
      )

      const messagesPostbackButtonList = splitInWhatsappListButtons(
        postbackButtonElements
      )

      const messages = messagesPostbackButtonList.map(
        (postbackButtons, index) => {
          if (postbackButtons.length <= WHATSAPP_MAX_BUTTONS) {
            return {
              type: INPUT.TEXT,
              children: [...buttonsTextSeparator, ...postbackButtons],
            }
          }
          const rows = postbackButtons.map(postbackButton => {
            const row = {
              id: postbackButton.props.path
                ? `__PATH_PAYLOAD__${postbackButton.props.path}`
                : postbackButton.props.payload,
              title: postbackButton.props.children,
            }
            return row
          })
          const whatsAppButtonListProps = {
            body: index === 0 ? texts.join('') : buttonsTextSeparator,
            button: menuButtonTextWhatsappList,
            sections: [{ rows }],
          }

          return {
            type: INPUT.WHATSAPP_BUTTON_LIST,
            props: whatsAppButtonListProps,
          }
        }
      )

      const messageWithUrlButtonElements = (
        <Text
          key={`msg-with-url-button`}
          {...MULTICHANNEL_WHATSAPP_PROPS}
          {...props}
        >
          {urlButtonElements}
        </Text>
      )

      const messageWithWebviewButtonElements = (
        <Text
          key={`msg-with-webview-button`}
          {...MULTICHANNEL_WHATSAPP_PROPS}
          {...props}
        >
          {buttonsTextSeparator}
          {webviewButtonElements}
        </Text>
      )

      return (
        <>
          {messages.map((message, i) => {
            if (message.type === INPUT.WHATSAPP_BUTTON_LIST) {
              return (
                <WhatsappButtonList
                  key={`msg-${i}-whatsapp-list`}
                  {...message.props}
                />
              )
            }
            return (
              <Text
                key={`msg-${i}-with-postback-buttons`}
                {...MULTICHANNEL_WHATSAPP_PROPS}
                {...props}
              >
                {message.children}
              </Text>
            )
          })}
          {urlButtonElements.length > 0 && messageWithUrlButtonElements}
          {webviewButtonElements.length > 0 && messageWithWebviewButtonElements}
        </>
      )
    }

    multichannelContext.currentIndex = getDefaultIndex()
    const postbackButtonElements = postbackButtons.map(
      regenerateMultichannelButtons(!!texts.length)
    )
    const urlButtonElements = urlButtons.map(
      regenerateMultichannelButtons(!!texts.length || !!postbackButtons.length)
    )

    elements = [].concat(
      [...textElements],
      [...postbackButtonElements],
      [...urlButtonElements]
    )

    if (postbackButtonElements.length === 0) {
      // Use texts[0] instead of textElements[0] as a body to avoid apply the markdownMeta function twice.
      // If the markdownMeta function is applied twice, bold is replaced by italics.
      const body = texts[0] || ''

      if (urlButtonElements.length === 1) {
        return (
          <WhatsappCTAUrlButton
            body={body}
            displayText={urlButtonElements[0].props.children}
            url={urlButtonElements[0].props.url}
          />
        )
      }

      if (webviewButtonElements.length === 1) {
        return (
          <WhatsappCTAUrlButton
            body={body}
            displayText={webviewButtonElements[0].props.children}
            webview={webviewButtonElements[0].props.webview}
            params={webviewButtonElements[0].props.params}
          />
        )
      }
    }

    if (multichannelContext.messageSeparator != null) {
      return elements
    }
    const messages = [
      <Text key={0} {...MULTICHANNEL_WHATSAPP_PROPS} {...props}>
        {elements}
      </Text>,
    ]
    if (webviewButtonElements.length) {
      messages.push(
        <Text key={1} {...MULTICHANNEL_WHATSAPP_PROPS} {...props}>
          {buttonsTextSeparator}
          {webviewButtonElements}
        </Text>
      )
    }

    return <>{messages}</>
  }

  if (
    isFacebook(requestContext.session) ||
    isInstagram(requestContext.session)
  ) {
    const text = getText(props.children)
    const multichannelFacebook = new MultichannelFacebook()
    const { texts, propsLastText, propsWithoutChildren } =
      multichannelFacebook.convertText(props, text[0])

    const [lastText, ...buttonsAndReplies] = propsLastText.children
    const replies = []

    if (buttonsAndReplies.length > 3) {
      buttonsAndReplies.forEach(button => {
        if (isNodeButton(button)) {
          replies.push(<Reply {...button.props} />)
        }
      })
    }

    return (
      <>
        {texts?.map((message, i) => (
          <Text key={`msg-${i}-text`} {...propsWithoutChildren}>
            {convertToMarkdownMeta(message)}
          </Text>
        ))}
        <Text {...propsLastText}>
          {convertToMarkdownMeta(lastText)}
          {replies.length > 0 ? replies : buttonsAndReplies}
        </Text>
      </>
    )
  }

  return <Text {...props}>{props.children}</Text>
}
