import React from 'react'
import Filters from './Filters'
import Listings from './Listings'
import ListingDetails from './ListingDetails'
import ContactModal from './ContactModal'
import {pacSelectFirst} from '../helpers/googleMaps'
import {loadProperties, loadSeen, loadListing} from '../lib/api'
import {handleMessage} from '../lib/handlers'
import Router from '../lib/router'
import {isMobile} from '../lib/helpers'

class Main extends React.Component {
  constructor (props) {
    super(props)

    const state = {
      listingDetails: false,
      listings: new Map(),
      imageIndex: 0,
      page: 0,
      sort: 'relevance',
      filters: {
        rooms: {},
        category: {},
        status : {},
        adType: 0
      },
      mobileView: 'MAP',
      contact: {
        message: '',
        name: '',
        email: '',
        phone: '',
        valid: true
      }
    }

    console.log("Props : ");
    console.log(props.initialState);
    if (props.initialState) {
      props.initialState.sort = props.initialState.sort || state.sort
      state.filters.rooms = props.initialState.rooms
      state.filters.category = props.initialState.category
      state.sort = props.initialState.sort || state.sort
      state.listingId = props.initialState.listingId
      state.bounds = props.initialState.bounds
      state.zoom = props.initialState.zoom
      if (state.listingId) {
        state.listingDetails = true
      }
      state.filters.minSize = props.initialState.minSize
      state.filters.maxSize = props.initialState.maxSize
      state.filters.minPrice = props.initialState.minPrice
      state.filters.maxPrice = props.initialState.maxPrice
      state.filters.adType = props.initialState.adType
    }

    this.state = state
    this.router = new Router(this, props.initialState)
  }

  dispatch ({type, action = {}}) {
    handleMessage({type, action}, this)
  }

  componentDidMount () {
    const uluru = {lat: 43.845031, lng: 18.4019262}
    const opts = {
      //zoom: 13,
      //center: uluru,
      streetViewControl: false,
      mapTypeControl: false
    }

    if (!this.state.bounds) {
      opts.zoom = 13
      opts.center = uluru
    }

    const map = new google.maps.Map(this.refs.map, opts)
    window.gmap = map

    //const marker = new google.maps.Marker({
    //position: uluru,
    //map: map
    //});

    var control = document.createElement('div')
    control.classList.add('filters-btn-toggle')
    control.innerHTML = '<button>Filteri</button>'
    //control.style = "top: 200px;"
    // TODO: enable this
    //control['style'] = 'top: 200px;'

    var input = document.getElementById('gmaps-places-input')

    pacSelectFirst(input)
    input.addEventListener('focus', (e) => {
      e.target.value = '';
    });

    var options = {
      componentRestrictions: {country: 'BA'},
      types: [ 'geocode' ]
    }

    const regularIdle = () => {
      this.dispatch({
        type: 'UPDATE_ROUTE',
        action: {
          params: {
            bounds: map.getBounds().toUrlValue(),
            zoom: map.getZoom()
          }
        }
      })

      this.dispatch({type: 'MAP_IDLE'})
    }

    // Check if initial bounds are passed-in

    google.maps.event.addListenerOnce(map, 'idle', () => {
      if (this.state.bounds) {
        const [lat1, lng1, lat2, lng2] = this.state.bounds.split(',')
        const sw = new google.maps.LatLng({
          lat: parseFloat(lat1),
          lng: parseFloat(lng1)
        })
        const ne = new google.maps.LatLng({
          lat: parseFloat(lat2),
          lng: parseFloat(lng2)
        })

        const initialBounds = new google.maps.LatLngBounds(sw, ne)
        //map.fitBounds(initialBounds);

        const originalMaxZoom = map.maxZoom
        const originalMinZoom = map.minZoom
        map.setOptions({
          maxZoom: parseInt(this.state.zoom),
          minZoom: parseInt(this.state.zoom)
        })

        map.fitBounds(initialBounds)
        map.setOptions({maxZoom: originalMaxZoom, minZoom: originalMinZoom})
        if (isMobile()) {
          document.getElementById('left').classList.add("left-absolute");
          this.addAbsoluteLeftInRender = true;
        }
      }
    })
    map.addListener('idle', regularIdle)
    var searchBox = new google.maps.places.Autocomplete(input, options)

    searchBox.addListener('place_changed', () => {
      var place = searchBox.getPlace()

      if (!place.geometry) {
        return
      }

      if (place.geometry.viewport) {
        console.log('we have viewport', place);

        if (this.state.mobileView === 'MAP') {
          map.fitBounds(place.geometry.viewport)
        } else {
          this.dispatch({type: 'MOBILE_MAP_VIEW'})
          map.fitBounds(place.geometry.viewport)
        }

        map.setZoom(map.zoom + 1);
      } else {
        map.setCenter(place.geometry.location)
        map.setZoom(18)
      }

      document.activeElement.blur();
      this.dispatch({type: 'SEARCH_PLACE_CHANGED'})
    })

    control.addEventListener('click', e => {
      this.dispatch({
        type: 'OPEN_FILTERS'
      })
    })

    control.index = 1
    map.controls[google.maps.ControlPosition.TOP_RIGHT].push(control)
    this.map = map
  }

  removeAllMarkers () {
    if (this.markers) {
      this.markers.forEach(m => m.marker.setMap(null))
    }
  }

  onCloseClick (e) {
    if (this.state.filtersOpen) {
      console.log('FILTERS WERE OPEN')
      //setTimeout(
        //() => {
          //google.maps.event.trigger(this.map, 'resize')
        //},
        //100
      //)
    }

    this.dispatch({
      type: 'CLOSE_FILTERS'
    })
    //this.setState({
      //mapClicked: false
    //})
  }

  findMarker (id) {
    if (!this.markers) {
      return null
    }

    const index = this.markers.findIndex(m => m.id === id)
    return this.markers[index]
  }

  isSeen (id) {
    const seen = loadSeen()
    return seen.findIndex(s => s === id) !== -1
  }

  loadPins () {
    const map = this.map
    const {
      rooms,
      minSize,
      maxSize,
      minPrice,
      maxPrice,
      category,
      adType
    } = this.state.filters

    const bounds = map.getBounds()
    const properties = loadProperties({
      bounds: bounds.toUrlValue(),
      rooms,
      minSize,
      maxSize,
      minPrice,
      maxPrice,
      category,
      adType,
      page: this.state.page,
      pins: true
    })

    const markerExists = id => {
      return this.findMarker(id) != null
    }

    properties
      .then(p => {
        return {
          body: p.text(),
          totalCount: p.headers.get('X-Total-Count')
        }
      })
      .then(({body, totalCount}) => {
        body.then(p => {
          const data = JSON.parse(p)

          const listingExists = id => {
            return data.findIndex(l => l._id === id) !== -1
          }

          const newMarkers = []

          if (this.markers) {
            this.markers.forEach(m => {
              if (!listingExists(m.id)) {
                m.marker.setMap(null)
              } else {
                newMarkers.push(m)
              }
            })
          }

          for (const [index, prop] of data.entries()) {
            const myLatLng = {lat: prop.loc[0], lng: prop.loc[1]}

            if (!markerExists(prop._id)) {
              const marker = new google.maps.Marker({
                position: myLatLng,
                map: map,
                //title    : prop.title,
                icon: this.isSeen(prop._id)
                  ? this.visitedMarkerIcon()
                  : this.defaultMarkerIcon(),
                id: prop._id
              })

              marker.addListener('mouseover', () => {
                if (marker.id !== this.state.listingId) {
                  if (this.isSeen(marker.id)) {
                    marker.setIcon(this.visitedHoveredMarkerIcon())
                  } else {
                    marker.setIcon(this.hoveredMarkerIcon())
                  }
                }
              })

              marker.addListener('mouseout', () => {
                if (marker.id !== this.state.listingId) {
                  if (this.isSeen(marker.id)) {
                    marker.setIcon(this.visitedMarkerIcon())
                  } else {
                    marker.setIcon(this.defaultMarkerIcon())
                  }
                }
              })

              marker.addListener('click', () => {
                // Maybe move out and call when popping state
                if (this.state.listingId) {
                  const prevSelected = this.findMarker(this.state.listingId)
                  if (prevSelected) {
                    prevSelected.marker.setIcon(this.visitedMarkerIcon())
                  }
                }

                marker.setIcon(this.selectedMarkerIcon())

                loadListing(prop._id).then(l => l.text()).then(l => {
                  this.dispatch({
                    type: 'UPDATE_ROUTE',
                    action: {
                      toDispatch: {
                        type: 'VIEW_LISTING_DETAILS',
                        action: {
                          id: prop._id,
                          listing: JSON.parse(l)
                        }
                      },
                      params: {
                        listingId: prop._id
                      }
                    }
                  })

                  //this.dispatch({type: 'UPDATE_ROUTE', action: {type: 'VIEW_LISTING_DETAILS', action: {
                  //id: prop._id,
                  //listing: JSON.parse(l)
                  //}}});

                  this.dispatch({
                    type: 'VIEW_LISTING_DETAILS',
                    action: {
                      id: prop._id,
                      listing: JSON.parse(l)
                    }
                  })
                })
              })

              newMarkers.push({
                marker,
                id: prop._id
              })
            }
          }

          this.dispatch({
            type: 'PINS_LOADED',
            action: {
              newMarkers
            }
          })
        })
      })
  }

  /*
   * Refreshes search
   */
  refreshListings (more = false) {
    // TODO: move somewhere else

    if (!more && this.state.listingId) {
      loadListing(this.state.listingId).then(l => l.text()).then(l => {
        this.dispatch({
          type: 'VIEW_LISTING_DETAILS',
          action: {
            id: this.state.listingId,
            listing: JSON.parse(l)
          }
        })
      })
    }

    if (!more) {
      this.loadPins()
    }

    const map = this.map
    const {
      rooms,
      minSize,
      maxSize,
      minPrice,
      maxPrice,
      category,
      adType
    } = this.state.filters

    const bounds = map.getBounds()
    const properties = loadProperties({
      bounds: bounds.toUrlValue(),
      rooms,
      minSize,
      maxSize,
      minPrice,
      maxPrice,
      category,
      adType,
      page: this.state.page,
      sort: this.state.sort
    })

    properties
      .then(p => {
        return {
          body: p.text(),
          totalCount: p.headers.get('X-Total-Count')
        }
      })
      .then(({body, totalCount}) => {
        body.then(p => {
          const data = JSON.parse(p)

          this.dispatch({
            type: 'LISTINGS_LOADED',
            action: {
              listings: data,
              more,
              totalCount
            }
          })
        })
      })
  }

  /*
   * Get default marker icon
   */
  defaultMarkerIcon () {
    const sf = 0.5
    const width = 48
    const height = 64
    const icon = {
      url: 'static/images/pins_sprite.png',
      size: new google.maps.Size(width * sf, height * sf),
      scaledSize: new google.maps.Size(730 * sf, 102 * sf),
      origin: new google.maps.Point(0, 36 * sf)
    }

    return icon
  }

  /*
   * Get visited marker icon
   */
  visitedMarkerIcon () {
    const sf = 0.5
    const width = 48
    const height = 64
    const icon = {
      url: 'static/images/pins_sprite.png',
      size: new google.maps.Size(width * sf, height * sf),
      scaledSize: new google.maps.Size(730 * sf, 102 * sf),
      origin: new google.maps.Point(152 * sf, 36 * sf)
    }

    return icon
  }

  /*
   * Visited hovered marker icon
   */
  visitedHoveredMarkerIcon () {
    const sf = 0.5
    const width = 61
    const height = 82
    const icon = {
      url: 'static/images/pins_sprite.png',
      size: new google.maps.Size(width * sf, height * sf),
      scaledSize: new google.maps.Size(730 * sf, 102 * sf),
      origin: new google.maps.Point(480 * sf, 18 * sf)
    }

    return icon
  }

  /*
   * Hovered marker icon
   */
  hoveredMarkerIcon () {
    const sf = 0.5
    const width = 61
    const height = 82
    const icon = {
      url: 'static/images/pins_sprite.png',
      size: new google.maps.Size(width * sf, height * sf),
      scaledSize: new google.maps.Size(730 * sf, 102 * sf),
      origin: new google.maps.Point(303 * sf, 18 * sf)
    }

    return icon
  }

  /*
   * Selected marker icon
   */
  selectedMarkerIcon () {
    const sf = 0.5
    const width = 73
    const height = 100
    const icon = {
      url: 'static/images/pins_sprite.png',
      size: new google.maps.Size(width * sf, height * sf),
      scaledSize: new google.maps.Size(730 * sf, 102 * sf),
      origin: new google.maps.Point(655 * sf, 1 * sf)
    }

    return icon
  }

  renderRightContent () {
    const children = []

    if (this.state.listingDetails) {
      const listing = this.state.listing //this.state.listings.get(this.state.listingId);
      children.push(
        <ListingDetails
          contactFormOpen={this.state.contactFormOpen}
          contact={this.state.contact}
          listing={listing}
          imageIndex={this.state.imageIndex}
          dispatch={this.dispatch.bind(this)}
          descriptionExpanded={this.state.descriptionExpanded}
        />
      )
    } else {
      children.push(
        <Filters
          filters={this.state.filters}
          dispatch={this.dispatch.bind(this)}
          onClose={this.onCloseClick.bind(this)}
        />
      )

      children.push(
        <Listings
          sort={this.state.sort}
          totalCount={this.state.totalCount}
          loadingMore={this.state.loadingMore}
          listings={this.state.listings}
          dispatch={this.dispatch.bind(this)}
        />
      )
    }
    const content = (
      <div className="right-content">
        {children}
      </div>
    )

    return content
  }

  onMobileListViewClick (e) {
    e.preventDefault()
    this.dispatch({
      type: 'MOBILE_LIST_VIEW'
    })
  }

  onMobileMapViewClick (e) {
    e.preventDefault()
    this.dispatch({
      type: 'MOBILE_MAP_VIEW'
    })
  }

  render () {
    const leftStyle = {}
    const rightStyle = {}
    const listingDetails = true

    let leftClass = 'left-base'
    let rightClass = 'right-base'

    if (this.state.listingId || this.state.filtersOpen) {
      leftClass = this.addAbsoluteLeftInRender ? 'left-absolute' : ''
      rightClass = 'right-shown'
    }

    const {contactFormOpen} = this.state
    const isMapView = this.state.mobileView === 'MAP'

    return (
      <div id="container">
        {contactFormOpen ? <ContactModal
          listingId={this.state.listing._id}
          contact={this.state.contact}
          dispatch={this.dispatch.bind(this)} /> : null}
        <div id="header">
          <a className="hamburger-menu">K</a>
          <span className="title">KIVI</span>
          <input
            id="gmaps-places-input"
            placeholder="Unesite adresu, naselje ili grad"
            className="where-to"
            type="text"
          />
          <div className="view-types">
            <a onClick={this.onMobileListViewClick.bind(this)} className={!isMapView ? "view-type-left selected": "view-type-left"}>
              <i className="btn-select-map fa fa-list" />
            </a>
            <a onClick={this.onMobileMapViewClick.bind(this)} className={isMapView ? "view-type-right selected": "view-type-right"}>
              <i className="view-type-map-icon fa fa-map-marker" />
            </a>
          </div>
        </div>

        <div id="right" style={rightStyle} className={rightClass}>
          {this.renderRightContent()}
        </div>

        <div id="left" style={leftStyle} className={leftClass}>
          {this.state.mobileView === 'LIST' && !this.state.listingDetails  &&
          <div className={ this.state.filtersOpen ? "map-list-view hide": "map-list-view" }>
        <Listings
          sort={this.state.sort}
          totalCount={this.state.totalCount}
          loadingMore={this.state.loadingMore}
          listings={this.state.listings}
          dispatch={this.dispatch.bind(this)}
        />
          </div>}
          <div id="map" ref="map" className={this.state.mobileView !== 'MAP' && "hide"} />
        </div>
      </div>
    )
  }
}
export default Main
