import Cookies from "js-cookie";
import React, { Component } from "react";
import Geocode from "react-geocode";
import Autocomplete from "react-google-autocomplete";
import {
  GoogleMap,
  InfoWindow,
  Marker,
  withGoogleMap,
  withScriptjs,
} from "react-google-maps";
import { GoogleMapsAPI } from "./client-config";

Geocode.setApiKey(GoogleMapsAPI);
Geocode.enableDebug();

class Map extends Component {
  constructor(props) {
    super(props);
    this.state = {
      address: "",
      city: "",
      area: "",
      state: "",
      mapPosition: {
        lat: this.props.center.lat,
        lng: this.props.center.lng,
      },
      markerPosition: {
        lat: this.props.center.lat,
        lng: this.props.center.lng,
      },
    };
  }

  /**
   * Get the current address from the default map position and set those values in the state
   */
  componentDidMount() {
    Geocode.fromLatLng(
      this.state.mapPosition.lat,
      this.state.mapPosition.lng,
    ).then(
      (response) => {
        const address = response.results[0].formatted_address;
        const addressArray = response.results[0].address_components;
        const city = this.getCity(addressArray);
        const area = this.getArea(addressArray);
        const state = this.getState(addressArray);

        console.log("city", city, area, state);

        this.setState({
          address: address || "",
          area: area || "",
          city: city || "",
          state: state || "",
        });
      },
      (error) => {
        console.error(error);
      },
    );
  }

  /**
   * Component should only update ( meaning re-render ), when the user selects the address, or drags the pin
   *
   * @param nextProps
   * @param nextState
   * @return {boolean}
   */
  shouldComponentUpdate(nextProps, nextState) {
    if (
      this.state.markerPosition.lat !== this.props.center.lat ||
      this.state.address !== nextState.address ||
      this.state.city !== nextState.city ||
      this.state.area !== nextState.area ||
      this.state.state !== nextState.state
    ) {
      return true;
    }

    if (this.props.center.lat == nextProps.center.lat) {
      return false;
    }
  }

  /**
   * Get the city and set the city input value to the one selected
   *
   * @param addressArray
   * @return {string}
   */
  getCity = (addressArray) => {
    let city = "";

    for (const element of addressArray) {
      if (
        element.types[0] &&
        element.types[0] == "administrative_area_level_2"
      ) {
        city = element.long_name;
        return city;
      }
    }
  };
  /**
   * Get the area and set the area input value to the one selected
   *
   * @param addressArray
   * @return {string}
   */
  getArea = (addressArray) => {
    let area = "";

    for (const element of addressArray) {
      if (element.types[0]) {
        for (let j = 0; j < element.types.length; j++) {
          if (
            element.types[j] == "sublocality_level_1" ||
            element.types[j] == "locality"
          ) {
            area = element.long_name;
            return area;
          }
        }
      }
    }
  };
  /**
   * Get the address and set the address input value to the one selected
   *
   * @param addressArray
   * @return {string}
   */
  getState = (addressArray) => {
    let state = "";

    for (let i = 0; i < addressArray.length; i++) {
      for (const element of addressArray) {
        if (
          element.types[0] &&
          element.types[0] == "administrative_area_level_1"
        ) {
          state = element.long_name;
          return state;
        }
      }
    }
  };
  /**
   * And function for city,state and address input
   * @param event
   */
  onChange = (event) => {
    this.setState({
      [event.target.name]: event.target.value,
    });
  };
  /**
   * This Event triggers when the marker window is closed
   *
   * @param event
   */
  onInfoWindowClose = () => {};
  /**
   * When the marker is dragged you get the lat and long using the functions available from event object.
   * Use geocode to get the address, city, area and state from the lat and lng positions.
   * And then set those values in the state.
   *
   * @param event
   */
  onMarkerDragEnd = (event) => {
    const newLat = event.latLng.lat();
    const newLng = event.latLng.lng();

    Geocode.fromLatLng(newLat, newLng).then(
      (response) => {
        const address = response.results[0].formatted_address;
        const addressArray = response.results[0].address_components;
        const city = this.getCity(addressArray);
        const area = this.getArea(addressArray);
        const state = this.getState(addressArray);

        this.setState({
          address: address || "",
          area: area || "",
          city: city || "",
          state: state || "",
          markerPosition: {
            lat: newLat,
            lng: newLng,
          },
          mapPosition: {
            lat: newLat,
            lng: newLng,
          },
        });
        Cookies.set("map_lat", `${newLat}`, {
          expires: 1
        });
        Cookies.set("map_long", `${newLng}`, {
          expires: 1
        });
        $(".input-location-schedule").val(address);
      },
      (error) => {
        console.error(error);
      },
    );
  };
  /**
   * When the user types an address in the search box
   * @param place
   */
  onPlaceSelected = (place) => {
    console.log("plc", place);
    const address = place.formatted_address;
    const addressArray = place.address_components;
    const city = this.getCity(addressArray);
    const area = this.getArea(addressArray);
    const state = this.getState(addressArray);
    const latValue = place.geometry.location.lat();
    const lngValue = place.geometry.location.lng();

    // Set these values in the state.
    this.setState({
      address: address || "",
      area: area || "",
      city: city || "",
      state: state || "",
      markerPosition: {
        lat: latValue,
        lng: lngValue,
      },
      mapPosition: {
        lat: latValue,
        lng: lngValue,
      },
    });
    Cookies.set("map_lat", `${latValue}`, {
      expires: 1
    });
    Cookies.set("map_long", `${lngValue}`, {
      expires: 1
    });
    $(".input-location-schedule").val(address);
  };
  render() {
    const AsyncMap = withScriptjs(
      withGoogleMap(() => (
        <GoogleMap
          google={this.props.google}
          defaultZoom={this.props.zoom}
          defaultCenter={{
            lat: this.state.mapPosition.lat,
            lng: this.state.mapPosition.lng,
          }}
        >
          <Autocomplete
            style={{
              width: "100%",
              height: "40px",
              paddingLeft: "16px",
              marginTop: "2px",
              marginBottom: "500px",
            }}
            onPlaceSelected={this.onPlaceSelected}
            options={{
              types: ["geocode"],
            }}
          />
          {/* InfoWindow on top of marker */}
          <InfoWindow
            onClose={this.onInfoWindowClose}
            position={{
              lat: this.state.markerPosition.lat + 0.0018,
              lng: this.state.markerPosition.lng,
            }}
          >
            <div>
              <span
                style={{
                  padding: 0,
                  margin: 0,
                }}
              >
                {this.state.address}
              </span>
            </div>
          </InfoWindow>
          {/* Marker */}
          <Marker
            google={this.props.google}
            name="Dolores park"
            draggable={this.props.draggable}
            onDragEnd={this.onMarkerDragEnd}
            position={{
              lat: this.state.markerPosition.lat,
              lng: this.state.markerPosition.lng,
            }}
          />
          <Marker />
          {/* For Auto complete Search Box */}
        </GoogleMap>
      )),
    );

    let map;

    if (this.props.center.lat == undefined) {
      map = (
        <div
          style={{
            height: this.props.height,
          }}
        />
      );
    } else {
      map = (
        <div>
          {/* <div>
					<div className="form-group">
						<label htmlFor="">Address</label>
						<input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.address }/>
					</div>
                    <div className="form-group">
						<label htmlFor="">All Data</label>
						<input type="text" name="address" className="form-control" onChange={ this.onChange } readOnly="readOnly" value={ this.state.markerPosition.lat + ";" + this.state.markerPosition.lng }/>
					</div>
				</div> */}
          <AsyncMap
            googleMapURL={`https://maps.googleapis.com/maps/api/js?key=${GoogleMapsAPI}&libraries=places`}
            loadingElement={
              <div
                style={{
                  height: "100%",
                }}
              />
            }
            containerElement={
              <div
                style={{
                  height: this.props.height,
                }}
              />
            }
            mapElement={
              <div
                style={{
                  height: "100%",
                }}
              />
            }
          />
        </div>
      );
    }

    return map;
  }
}

export default Map;
