// HOC to add a paste button to a text input

import Clipboard from '@react-native-clipboard/clipboard'
import * as React from 'react'
import { AppState, NativeEventSubscription, ViewProps } from 'react-native'
import { deviceIsIos14OrNewer } from 'src/utils/IosVersionUtils'
import Logger from 'src/utils/Logger'

const TAG = 'WithPasteAware'

interface PasteAwareProps {
  value: string
  shouldShowClipboard: (value: string) => boolean
  onChangeText: (text: string) => void
  leftIcon?: React.ReactNode
}

export interface PasteAwareWrappedElementProps {
  isPasteIconVisible: boolean
  onPressPaste: () => void
  onChangeText: (text: string) => void
  clipboardContent: string | null
  leftIcon?: React.ReactNode
}

interface PasteAwareState {
  isPasteIconVisible: boolean
  clipboardContent: string | null
}

export function withPasteAware<P extends ViewProps>(
  WrappedView: React.ComponentType<P & PasteAwareWrappedElementProps>
) {
  return class WithPasteAware extends React.Component<P & PasteAwareProps> {
    state: PasteAwareState = {
      isPasteIconVisible: false,
      clipboardContent: null,
    }

    _interval?: number
    _isMounted = false
    _appStateListener: NativeEventSubscription | null = null

    async componentDidMount() {
      this._isMounted = true
      this._appStateListener = AppState.addEventListener('change', this.checkClipboardContents)
      // TODO: make it work for iOS 14
      // https://9to5mac.com/2020/06/24/ios-14-clipboard-notifications/
      this._interval = window.setInterval(async () => {
        await this.checkClipboardContents()
      }, 1000) // Every 1s
      await this.checkClipboardContents()
    }

    componentWillUnmount() {
      this._isMounted = false
      this._appStateListener?.remove()
      clearInterval(this._interval)
    }

    checkClipboardContents = async () => {
      try {
        if (!this._isMounted) {
          return
        }

        if (deviceIsIos14OrNewer()) {
          const clipboardHasContent = await Clipboard.hasString()
          this.setState({ isPasteIconVisible: clipboardHasContent, clipboardContent: null })
          return
        }

        const clipboardContent = await Clipboard.getString()
        const { shouldShowClipboard, value } = this.props
        if (
          clipboardContent &&
          !(value && clipboardContent.toLowerCase().includes(value.toLowerCase())) &&
          shouldShowClipboard(clipboardContent)
        ) {
          this.setState({ isPasteIconVisible: true, clipboardContent })
        } else {
          this.setState({ isPasteIconVisible: false, clipboardContent: null })
        }
      } catch (error) {
        Logger.warn(TAG, 'Error checking clipboard contents', error)
      }
    }

    onPressPaste = async () => {
      const { clipboardContent: storedClipboardContent } = this.state
      const clipboardContent = storedClipboardContent || (await Clipboard.getString())
      if (!clipboardContent) {
        Logger.warn(TAG, 'Attempted to paste but clipboard content empty. Should never happen.')
        return
      }
      this.setState({ isPasteIconVisible: false, clipboardContent: null })
      this.props.onChangeText(clipboardContent)
    }

    render() {
      const { isPasteIconVisible } = this.state

      return (
        <WrappedView
          {...this.props}
          isPasteIconVisible={isPasteIconVisible}
          onPressPaste={this.onPressPaste}
          clipboardContent={this.state.clipboardContent}
        />
      )
    }
  }
}
