import {markSeen} from './api'
import {defaultContactMessage, listingUrl} from './helpers'

const setMaxPrice = ({type, action}, component) => {
  const maxPrice = parseFloat(action.maxPrice)
  component.setState({
    page: 0,
    filters: {
      ...component.state.filters,
      maxPrice: isNaN(maxPrice) ? undefined : maxPrice,
      priceDirty: true
    }
  })
}

const setMinPrice = ({type, action}, component) => {
  const minPrice = parseFloat(action.minPrice)
  component.setState({
    page: 0,
    filters: {
      ...component.state.filters,
      minPrice: isNaN(minPrice) ? undefined : minPrice,
      priceDirty: true
    }
  })
}

const setMinSize = ({type, action}, component) => {
  const minSize = parseFloat(action.minSize)
  component.setState({
    page: 0,
    filters: {
      ...component.state.filters,
      minSize: isNaN(minSize) ? undefined : minSize,
      sizeDirty: true
    }
  })
}

const setMaxSize = ({type, action}, component) => {
  const maxSize = parseFloat(action.maxSize)
  component.setState({
    page: 0,
    filters: {
      ...component.state.filters,
      maxSize: isNaN(maxSize) ? undefined : maxSize,
      sizeDirty: true
    }
  })
}

const getScrollElem = (component) => {
  const {mobileView} = component.state
  const scrollElem = mobileView === 'LIST' ?
    document.querySelector('.map-list-view') : document.querySelector('.right-content')

  return scrollElem
}

const viewListingDetails = ({type, action}, component) => {
  const scrollElem = getScrollElem(component)
  component.savedScrollTop = scrollElem.scrollTop

  component.setState(
    {
      listingDetails: true,
      listingId: action.id,
      descriptionExpanded: false,
      imageIndex: 0,
      listing: action.listing
    },
    () => {
      markSeen(action.id)
      const m = component.findMarker(action.id)
      if (m) {
        m.marker.setIcon(component.selectedMarkerIcon())
      }

      scrollElem.scrollTop = 0
    }
  )
}

const listingsLoaded = ({type, action}, component) => {
  const currentListings = new Map()

  for (const listing of action.listings) {
    currentListings.set(listing._id, listing)
  }

  component.setState({
    listings: action.more
      ? new Map([...component.state.listings, ...currentListings])
      : currentListings,
    loadingMore: false,
    totalCount: action.totalCount
  })
}

const pinsLoaded = ({type, action}, component) => {
  component.setState({}, () => {
    component.markers = action.newMarkers
  })
}

const expandDescription = ({type, action}, component) => {
  component.setState({
    descriptionExpanded: true
  })
}

const prevImage = ({type, action}, component) => {
  const index = component.state.imageIndex
  if (index > 0) {
    component.setState({
      imageIndex: index - 1
    })
  }
}

const nextImage = ({type, action}, component) => {
  const index = component.state.imageIndex
  component.setState({
    imageIndex: index + 1
  })
}

const viewImage = ({type, action}, component) => {
  component.setState({
    imageIndex: action.index
  })
}

const searchPlaceChanged = ({type, action}, component) => {
  component.setState({
    listingDetails: false,
    listingId: null,
    page: 0
  })
}

const setRooms = ({type, action}, component) => {
  const prevRooms = component.state.filters.rooms || {}

  component.setState(
    {
      page: 0,
      filters: {
        ...component.state.filters,
        rooms: {
          ...prevRooms,
          [action.rooms]: !prevRooms[action.rooms]
        }
      }
    },
    () => {
      component.refreshListings()
    }
  )
}

const updateSearch = ({type, action}, component) => {
  component.setState(
    {
      filters: {
        ...component.state.filters,
        sizeDirty: false,
        priceDirty: false
      }
    },
    () => {
      component.refreshListings()
    }
  )
}

const setCategory = ({type, action}, component) => {
  const prevCategory = component.state.filters.category || {}

  component.setState(
    {
      page: 0,
      filters: {
        ...component.state.filters,
        category: {
          ...prevCategory,
          [action.category]: !prevCategory[action.category]
        }
      }
    },
    () => {
      component.refreshListings()
    }
  )
}

const onListingMouseOver = ({type, action}, component) => {
  const marker = component.findMarker(action.id)
  if (marker) {
    const seen = component.isSeen(action.id)
    if (seen) {
      marker.marker.setIcon(component.visitedHoveredMarkerIcon())
    } else {
      marker.marker.setIcon(component.hoveredMarkerIcon())
    }

    marker.marker.setAnimation(google.maps.Animation.BOUNCE)
    setTimeout(
      () => {
        marker.marker.setAnimation(null)

        if (seen) {
          marker.marker.setIcon(component.visitedMarkerIcon())
        } else {
          marker.marker.setIcon(component.defaultMarkerIcon())
        }
      },
      710
    )
  }
}

const backToResults = ({type, action}, component) => {
  const prevSelected = component.findMarker(component.state.listingId)
  component.setState(
    {
      listingId: null,
      listingDetails: false
    },
    () => {
      if (prevSelected) {
        prevSelected.marker.setIcon(component.visitedMarkerIcon())
      }

      //const scrollElem = document.querySelector('.right-content')
      const scrollElem = getScrollElem(component)
      scrollElem.scrollTop = component.savedScrollTop
    }
  )
}

const loadMoreListings = ({type, action}, component) => {
  const currentPage = component.state.page
  if (currentPage * 20 < component.state.totalCount) {
    component.setState(
      {
        loadingMore: true,
        page: currentPage + 1
      },
      () => {
        component.refreshListings(true)
      }
    )
  }
}

const mapIdle = ({type, action}, component) => {
  component.setState(
    {
      page: 0
    },
    () => {
      const scrollElem = getScrollElem(component)
      //const scrollElem = document.querySelector('.right-content')
      scrollElem.scrollTop = 0
      component.refreshListings()
    }
  )
}

const sortChange = ({type, action}, component) => {
  component.setState(
    {
      sort: action.sort,
      page: 0
    },
    () => {
      component.refreshListings()
    }
  )
}

const updateRoute = ({type, action}, component) => {
  component.router.update(action)
}

const openContact = ({type, action}, component) => {
  component.setState({
    contactFormOpen: true,
    contact: {
      ...component.state.contact,
      message: defaultContactMessage(listingUrl(component.state.listingId)),
      emailInvalid: false,
      nameInvalid: false,
      name: '',
      email: '',
      phone: ''
    }
  })
}

const closeContact = ({type, action}, component) => {
  component.setState({
    contactFormOpen: false
  })
}

const updateContactInfo = ({type, action}, component) => {

  let nameInvalid = component.state.contact.nameInvalid
  let emailInvalid = component.state.contact.emailInvalid

  if (action.field === 'name') {
    nameInvalid = !action.value
  }

  if (action.field === 'email') {
    emailInvalid = !action.value
  }

  component.setState({
    contact: {
      ...component.state.contact,
      [action.field]: action.value,
      ...{nameInvalid, emailInvalid}
    }
  })
}

const invalidContact = ({type, action}, component) => {
  const {name, email} = component.state.contact

  component.setState({
    contact: {
      ...component.state.contact,
      ...{nameInvalid: !name, emailInvalid: !email}
    }
  })
}

const submitContactStart = ({type, action}, component) => {
  component.setState({
    contact: {
      sending: true
    }
  })
}

const submitContactEnd = ({type, action}, component) => {
  component.setState({
    contactFormOpen: false,
    contact: {
      sending: false,
    }
  })
}

const mobileMapView = ({type, action}, component) => {

  component.setState({
    mobileView: 'MAP'
  }, () => {
    backToResults({type, action}, component)
  })
}

const mobileListView = ({type, action}, component) => {
  component.setState({
    mobileView: 'LIST'
  }, () => {
    backToResults({type, action}, component)
  })
}

const openFilters = ({type, action}, component) => {
  component.setState({
    filtersOpen: true
  })
}

const closeFilters = ({type, action}, component) => {
  component.setState({
    filtersOpen: false
  })
}

const resetFilters = ({type, action}, component) => {
  component.setState({
    filters: {
      rooms: {},
      category: {}
    }
  }, () => {
    component.router.reset()
  })
}

const handlers = {
  SET_MIN_PRICE: setMinPrice,
  SET_MAX_PRICE: setMaxPrice,
  SET_MIN_SIZE: setMinSize,
  SET_MAX_SIZE: setMaxSize,
  LISTINGS_LOADED: listingsLoaded,
  EXPAND_DESCRIPTION: expandDescription,
  PREV_IMAGE: prevImage,
  NEXT_IMAGE: nextImage,
  VIEW_IMAGE: viewImage,
  SEARCH_PLACE_CHANGED: searchPlaceChanged,
  SET_ROOMS: setRooms,
  VIEW_LISTING_DETAILS: viewListingDetails,
  UPDATE_SEARCH: updateSearch,
  SET_CATEGORY: setCategory,
  ON_LISTING_MOUSE_OVER: onListingMouseOver,
  BACK_TO_RESULTS: backToResults,
  LOAD_MORE_LISTINGS: loadMoreListings,
  MAP_IDLE: mapIdle,
  PINS_LOADED: pinsLoaded,
  SORT_CHANGE: sortChange,
  UPDATE_ROUTE: updateRoute,
  OPEN_CONTACT: openContact,
  CLOSE_CONTACT: closeContact,
  UPDATE_CONTACT_INFO: updateContactInfo,
  SUBMIT_CONTACT_START: submitContactStart,
  SUBMIT_CONTACT_END: submitContactEnd,
  INVALID_CONTACT: invalidContact,
  MOBILE_MAP_VIEW: mobileMapView,
  MOBILE_LIST_VIEW: mobileListView,
  OPEN_FILTERS: openFilters,
  CLOSE_FILTERS: closeFilters,
  RESET_FILTERS: resetFilters
}

export const handleMessage = ({type, action}, component) => {
  if (!handlers[type]) {
    throw new `Unhandled message: ${type}`()
  }

  console.log(type, action);
  return handlers[type]({type, action}, component)
}
