import { withRouter } from 'react-router'
import { connect } from 'react-redux'
import get from 'lodash.get'

import { btc } from 'lib/utils'

import { themeSelectors } from 'reducers/theme'
import { setCurrency, tickerSelectors } from 'reducers/ticker'
import { closeWalletModal } from 'reducers/address'
import { fetchInfo, infoSelectors } from 'reducers/info'
import { setFormType } from 'reducers/form'
import { createInvoice, fetchInvoice } from 'reducers/invoice'
import { lndSelectors } from 'reducers/lnd'
import {
  fetchChannels,
  fetchSuggestedNodes,
  openChannel,
  closeChannel,
  channelsSelectors,
  currentChannels,
  toggleFilterPulldown,
  changeFilter,
  updateChannelSearchQuery,
  setSelectedChannel
} from 'reducers/channels'
import {
  openContactsForm,
  closeContactsForm,
  setChannelFormType,
  openManualForm,
  closeManualForm,
  openSubmitChannelForm,
  closeSubmitChannelForm,
  updateContactFormSearchQuery,
  updateManualFormSearchQuery,
  updateContactCapacity,
  setNode,
  contactFormSelectors,
  updateManualFormErrors
} from 'reducers/contactsform'
import { fetchBalance } from 'reducers/balance'
import { fetchDescribeNetwork } from 'reducers/network'
import { clearError } from 'reducers/error'
import { hideActivityModal, activitySelectors } from 'reducers/activity'

import App from 'components/App'
import withLoading from 'components/withLoading'

const mapDispatchToProps = {
  setCurrency,
  closeWalletModal,
  fetchInfo,
  setFormType,
  createInvoice,
  fetchInvoice,
  clearError,
  fetchBalance,
  fetchChannels,
  fetchSuggestedNodes,
  openChannel,
  closeChannel,
  toggleFilterPulldown,
  changeFilter,
  updateChannelSearchQuery,
  setSelectedChannel,
  openContactsForm,
  closeContactsForm,
  openSubmitChannelForm,
  closeSubmitChannelForm,
  openManualForm,
  closeManualForm,
  updateContactFormSearchQuery,
  updateManualFormSearchQuery,
  updateContactCapacity,
  setNode,
  contactFormSelectors,
  updateManualFormErrors,
  setChannelFormType,
  fetchDescribeNetwork,
  hideActivityModal
}

const mapStateToProps = state => ({
  activity: state.activity,
  lnd: state.lnd,
  ticker: state.ticker,
  address: state.address,
  info: state.info,
  payment: state.payment,
  transaction: state.transaction,
  peers: state.peers,
  channels: state.channels,
  contactsform: state.contactsform,
  balance: state.balance,
  form: state.form,
  requestform: state.requestform,
  invoice: state.invoice,
  error: state.error,
  network: state.network,
  settings: state.settings,

  isLoading:
    infoSelectors.infoLoading(state) ||
    tickerSelectors.tickerLoading(state) ||
    state.balance.channelBalance === null ||
    state.balance.walletBalance === null,

  activityModalItem: activitySelectors.activityModalItem(state),
  currentTheme: themeSelectors.currentTheme(state),

  currentTicker: tickerSelectors.currentTicker(state),
  currencyFilters: tickerSelectors.currencyFilters(state),
  currencyName: tickerSelectors.currencyName(state),
  syncPercentage: lndSelectors.syncPercentage(state),

  filteredNetworkNodes: contactFormSelectors.filteredNetworkNodes(state),
  showManualForm: contactFormSelectors.showManualForm(state),
  manualFormIsValid: contactFormSelectors.manualFormIsValid(state),
  contactFormFiatAmount: contactFormSelectors.contactFormFiatAmount(state),
  dupeChanInfo: contactFormSelectors.dupeChanInfo(state),

  currentChannels: currentChannels(state),
  activeChannelPubkeys: channelsSelectors.activeChannelPubkeys(state),
  nonActiveChannelPubkeys: channelsSelectors.nonActiveChannelPubkeys(state),
  pendingOpenChannelPubkeys: channelsSelectors.pendingOpenChannelPubkeys(state),
  nonActiveFilters: channelsSelectors.nonActiveFilters(state),
  channelNodes: channelsSelectors.channelNodes(state)
})

const mergeProps = (stateProps, dispatchProps, ownProps) => {
  const formProps = formType => {
    if (!formType) {
      return {}
    }
    return {}
  }

  const networkTabProps = {
    currentChannels: stateProps.currentChannels,
    channels: stateProps.channels,
    balance: stateProps.balance,
    currentTicker: stateProps.currentTicker,
    contactsform: stateProps.contactsform,
    nodes: stateProps.network.nodes,
    nonActiveFilters: stateProps.nonActiveFilters,
    ticker: stateProps.ticker,
    network: stateProps.info.network,
    currencyName: stateProps.currencyName,

    fetchChannels: dispatchProps.fetchChannels,
    openContactsForm: dispatchProps.openContactsForm,
    contactFormSelectors: dispatchProps.contactFormSelectors,
    updateManualFormError: dispatchProps.updateManualFormErrors,
    toggleFilterPulldown: dispatchProps.toggleFilterPulldown,
    changeFilter: dispatchProps.changeFilter,
    updateChannelSearchQuery: dispatchProps.updateChannelSearchQuery,
    setSelectedChannel: dispatchProps.setSelectedChannel,
    closeChannel: dispatchProps.closeChannel,

    suggestedNodesProps: {
      suggestedNodesLoading: stateProps.channels.suggestedNodesLoading,
      suggestedNodes: stateProps.info.data.testnet
        ? stateProps.channels.suggestedNodes.testnet
        : stateProps.channels.suggestedNodes.mainnet,

      setNode: dispatchProps.setNode,
      openSubmitChannelForm: () => dispatchProps.setChannelFormType('SUBMIT_CHANNEL_FORM')
    }
  }

  const contactsFormProps = {
    closeContactsForm: dispatchProps.closeContactsForm,
    openSubmitChannelForm: () => dispatchProps.setChannelFormType('SUBMIT_CHANNEL_FORM'),
    updateContactFormSearchQuery: dispatchProps.updateContactFormSearchQuery,
    updateManualFormSearchQuery: dispatchProps.updateManualFormSearchQuery,
    updateContactCapacity: dispatchProps.updateContactCapacity,
    setNode: dispatchProps.setNode,
    openChannel: dispatchProps.openChannel,
    updateManualFormErrors: dispatchProps.updateManualFormErrors,
    openManualForm: () => dispatchProps.setChannelFormType('MANUAL_FORM'),

    contactsform: stateProps.contactsform,
    filteredNetworkNodes: stateProps.filteredNetworkNodes,
    loadingChannelPubkeys: stateProps.channels.loadingChannelPubkeys,
    showManualForm: stateProps.showManualForm,
    manualFormIsValid: stateProps.manualFormIsValid,
    activeChannelPubkeys: stateProps.activeChannelPubkeys,
    nonActiveChannelPubkeys: stateProps.nonActiveChannelPubkeys,
    pendingOpenChannelPubkeys: stateProps.pendingOpenChannelPubkeys
  }

  const activityModalProps = {
    itemType: stateProps.activity.modal.itemType,
    itemId: stateProps.activity.modal.itemId,
    item: stateProps.activityModalItem,

    ticker: stateProps.ticker,
    currentTicker: stateProps.currentTicker,
    network: stateProps.info.network,

    hideActivityModal: dispatchProps.hideActivityModal,

    toggleCurrencyProps: {
      currencyFilters: stateProps.currencyFilters,
      currencyName: stateProps.currencyName,
      setCurrency: dispatchProps.setCurrency
    }
  }

  const receiveModalProps = {
    isOpen: stateProps.address.walletModal,
    network: stateProps.info.network,
    pubkey: get(stateProps.info, 'data.uris[0]') || get(stateProps.info, 'data.identity_pubkey'),
    address: stateProps.address.address,
    alias: stateProps.info.data.alias,
    closeReceiveModal: dispatchProps.closeWalletModal
  }

  const submitChannelFormProps = {
    submitChannelFormOpen: stateProps.contactsform.submitChannelFormOpen,
    node: stateProps.contactsform.node,
    contactCapacity: stateProps.contactsform.contactCapacity,
    fiatTicker: stateProps.ticker.fiatTicker,
    dupeChanInfo: stateProps.dupeChanInfo,

    updateContactCapacity: dispatchProps.updateContactCapacity,

    closeChannelForm: () => dispatchProps.setChannelFormType(null),
    closeContactsForm: dispatchProps.closeContactsForm,

    openChannel: dispatchProps.openChannel,

    ticker: stateProps.ticker,

    toggleCurrencyProps: {
      currencyFilters: stateProps.currencyFilters,
      currencyName: stateProps.currencyName,
      contactFormFiatAmount: stateProps.contactFormFiatAmount,
      setCurrency: dispatchProps.setCurrency,
      onCurrencyFilterClick: currency => {
        dispatchProps.updateContactCapacity(
          btc.convert(stateProps.ticker.currency, currency, stateProps.contactsform.contactCapacity)
        )
        dispatchProps.setCurrency(currency)
      }
    }
  }

  const connectManuallyProps = {
    closeManualForm: dispatchProps.closeManualForm,
    updateManualFormSearchQuery: dispatchProps.updateManualFormSearchQuery,
    updateManualFormErrors: dispatchProps.updateManualFormErrors,
    setNode: dispatchProps.setNode,
    openSubmitChannelForm: () => dispatchProps.setChannelFormType('SUBMIT_CHANNEL_FORM'),

    manualFormOpen: stateProps.contactsform.manualFormOpen,
    manualSearchQuery: stateProps.contactsform.manualSearchQuery,
    manualFormIsValid: stateProps.manualFormIsValid,
    showErrors: stateProps.contactsform.showErrors
  }

  const calcChannelFormProps = formType => {
    if (formType === 'MANUAL_FORM') {
      return connectManuallyProps
    }
    if (formType === 'SUBMIT_CHANNEL_FORM') {
      return submitChannelFormProps
    }

    return {}
  }

  const channelFormProps = {
    formType: stateProps.contactsform.formType,
    formProps: calcChannelFormProps(stateProps.contactsform.formType),
    closeForm: () => dispatchProps.setChannelFormType(null)
  }

  return {
    ...stateProps,
    ...dispatchProps,
    ...ownProps,

    // props for the network sidebar
    networkTabProps,
    // props for the contacts form
    contactsFormProps,
    // props for the receive modal
    receiveModalProps,
    // props for the activity modals
    activityModalProps,
    // props for the form to open a channel
    submitChannelFormProps,
    // props for the form to connect manually to a peer
    connectManuallyProps,
    // props for the channel form wrapper
    channelFormProps,
    // Props to pass to the request form
    formProps: formProps(stateProps.form.formType),
    // action to close form
    closeForm: () => dispatchProps.setFormType(null)
  }
}

export default withRouter(
  connect(
    mapStateToProps,
    mapDispatchToProps,
    mergeProps
  )(withLoading(App))
)