/* eslint-disable max-classes-per-file */
import React, { Component, memo } from 'react'
import { View, Text, TextStyle, StyleSheet } from 'react-native'
import { connect } from 'react-redux'
import { isEqual } from 'lodash'
import PropTypes from 'prop-types'
import { dataTypes } from '@adalo/constants'

import { IObject } from 'interfaces'
import { solveBindings } from 'utils/library-binding'
import { deepSet } from 'utils/objects'
import { normalizeStyles } from 'utils/styles'

const libraryComponentManifest = {
  props: [
    {
      name: 'emptyStateTitleText',
      displayName: 'Title Text',
      type: dataTypes.TEXT,
      styles: {
        fontSize: 18,
        fontWeight: '500',
        fontStyle: 'normal',
        fontFamily: '@heading',
        color: '#656565',
      },
    },
    {
      name: 'emptyStateBodyText',
      displayName: 'Body Text',
      type: dataTypes.TEXT,
      styles: {
        fontSize: 12,
        fontWeight: '300',
        fontStyle: 'normal',
        fontFamily: '@body',
        color: '#757575',
      },
    },
  ],
}

type EmptyStateProps = {
  object: IObject
  componentProps:
    | {
        emptyStateTitleText?: string
        emptyStateBodyText?: string
        styles?: {
          emptyStateTitleText: TextStyle
          emptyStateBodyText: TextStyle
        }
      }
    | undefined
}

const critialProps = ['object', 'componentProps'] as const

class EmptyState extends Component<EmptyStateProps> {
  shouldComponentUpdate(
    nextProps: Readonly<EmptyStateProps>,
    nextState: Readonly<{}>,
    nextContext: any
  ): boolean {
    for (const prop of critialProps) {
      // eslint-disable-next-line react/destructuring-assignment
      if (!isEqual(this.props[prop], nextProps[prop])) {
        return true
      }
    }

    return false
  }

  render() {
    const { componentProps, object } = this.props

    if (!componentProps || !componentProps.styles) {
      return null
    }

    const {
      emptyStateTitleText,
      emptyStateBodyText,
      styles: componentPropStyles,
    } = componentProps
    const { emptyStateTitleText: titleStyles, emptyStateBodyText: bodyStyles } =
      componentPropStyles

    return (
      <View style={{ height: object.attributes.height }}>
        <View style={styles.container}>
          <Text style={[titleStyles, styles.text]}>{emptyStateTitleText}</Text>
          <Text style={[bodyStyles, styles.text]}>{emptyStateBodyText}</Text>
        </View>
      </View>
    )
  }
}

const styles = StyleSheet.create({
  container: {
    flex: 1,
    justifyContent: 'center',
    alignItems: 'center',
    padding: 16,
  },
  text: {
    textAlign: 'center',
  },
})

const mapStateToProps = (
  state: any,
  props: {
    object: IObject
    getApp: () => any
    getBinding: (id: string) => any
    getParams: () => any
    getImageUploadsBaseURL: () => string
  }
) => {
  const { object, getApp, getBinding, getParams, getImageUploadsBaseURL } =
    props

  const app = getApp()

  let { componentProps = {} } = solveBindings(
    app,
    {
      attributes: object.attributes,
      libraryComponentManifest,
    },
    {
      state,
      getBinding,
      getParams,
      getImageUploadsBaseURL,
    }
  )

  for (const prop of libraryComponentManifest.props) {
    if (prop.styles) {
      componentProps = deepSet(
        componentProps,
        ['styles', prop.name],
        normalizeStyles(prop, object.attributes, app.branding || {})
      )
    }
  }

  return {
    componentProps,
  }
}

const ConnectedEmptyState = connect(mapStateToProps)(EmptyState)

class WrappedEmptyState extends Component<{
  object: IObject
}> {
  static contextTypes = {
    getApp: PropTypes.func,
    getBinding: PropTypes.func,
    getParams: PropTypes.func,
    getImageUploadsBaseURL: PropTypes.func,
  }

  render() {
    const { getApp, getBinding, getParams, getImageUploadsBaseURL } =
      this.context

    const { object } = this.props

    return (
      <ConnectedEmptyState
        object={object}
        getApp={getApp}
        getBinding={getBinding}
        getParams={getParams}
        getImageUploadsBaseURL={getImageUploadsBaseURL}
      />
    )
  }
}

export default memo(WrappedEmptyState, isEqual)
