import React from 'react';
import ReactMapGL, { Marker } from 'react-map-gl';
import { Button } from "react-bootstrap";
import XmlReader from 'xml-reader';
import { withToastManager } from 'react-toast-notifications';
import PropTypes from 'prop-types';
import { haveSelectedGas, extractGasStationFromXml } from '../helpers';

import 'mapbox-gl/dist/mapbox-gl.css';

const mapboxToken = 'pk.eyJ1IjoiZGFya291IiwiYSI6ImNrNzkwdmlsdTBtMmwzZnM0ZmI4Z3h4czIifQ.GU2CdcMiKiApHNhI0ylGtQ';

class Map extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      viewport: {
        width: '100vw',
        height: '100vh',
        latitude: 44.837789,
        longitude: -0.57918,
        zoom: 11,
      },
      userLocation: {
        // latitude: 44.837789,
        // longitude: -0.57918,
      },
      gasStations: [],
    };

    this.mapRef = React.createRef();

    this.loadGasStations();
  }

  componentDidMount() {
    this.setUserLocation();
  }

  /**
   * Méthode permettant de mettre à jour la position de la map
   * @param {Object} viewport
   */
  onViewportChange = (viewport) => {
    this.setState({ viewport });
  }

  /**
   * Méthode permettant de sauvegarder la position de l'utilisateur
   */
  setUserLocation() {
    navigator.geolocation.getCurrentPosition((position) => {
      const setUserLocation = {
        latitude: position.coords.latitude,
        longitude: position.coords.longitude,
      };
      const newViewport = {
        height: '100vh',
        width: '100vw',
        latitude: position.coords.latitude,
        longitude: position.coords.longitude,
        zoom: 10,
      };
      this.setState({
        viewport: newViewport,
        userLocation: setUserLocation,
      });
    });
  }

  /**
   * Méthode permettant de filter sur la liste des stations affichables sur la carte
   * @param {Object} gasStation
   * @return {Boolean}
   */
  displayThisGasStation = (gasStation) => {
    const mapGL = this.mapRef.getMap();
    const bounds = mapGL.getBounds();

    return (bounds._ne.lat > gasStation.latitude && bounds._sw.lat < gasStation.latitude)
      && (bounds._ne.lng > gasStation.longitude && bounds._sw.lng < gasStation.longitude);
  }

  /**
   * Méthode permettant de charger le fichier xml contenant la liste des stations
   */
  loadGasStations() {
    const {
      toastManager,
    } = this.props;

    fetch('/gasStations.xml')
      .then((response) => response.text())
      .then((response) => {
        const reader = XmlReader.create();

        reader.on('done', (data) => {
          const pdv = data.children;

          const gasStations = [];

          for (let i = 0; i < pdv.length; i += 1) {
            const currentPdv = pdv[i];
            gasStations.push(extractGasStationFromXml(currentPdv));
          }

          this.setState((prevState) => ({
            ...prevState,
            gasStations,
          }));
        });
        reader.parse(response);
      }).catch(() => {
        toastManager.add('Erreur lors du chargement de la liste des stations', { appearance: 'error', autoDismiss: true });
      });
  }

  /**
   * Méthode gérant le rendu de la vue
   */
  render() {
    const {
      viewport,
      userLocation,
      gasStations,
    } = this.state;

    const {
      showGasStation,
      selectedGasType,
    } = this.props;

    return (
      <>
        <ReactMapGL
          {...viewport}
          mapStyle="mapbox://styles/mapbox/outdoors-v11"
          onViewportChange={this.onViewportChange}
          mapboxApiAccessToken={mapboxToken}
          ref={(map) => { if (map) this.mapRef = map; }}
        >
          {
            Object.keys(userLocation).length !== 0 ? (
              <Marker
                latitude={userLocation.latitude}
                longitude={userLocation.longitude}
              >
                <img className="locationIcon" src="/car.png" alt="My position" />
              </Marker>
            ) : (null)
          }
          {gasStations.filter(this.displayThisGasStation).filter((station) => haveSelectedGas(station, selectedGasType)).map((gasStation) => (
            <Marker
              key={gasStation.id}
              latitude={gasStation.latitude}
              longitude={gasStation.longitude}
            >
              <Button
                variant="link"
                onClick={() => showGasStation(gasStation)}
                onFocus={() => { }}
                onBlur={() => { }}
              >
                <img
                  className="locationIcon"
                  src="/gas-station.png"
                  alt={`${gasStation.id}`}
                />
              </Button>

            </Marker>
          ))}
        </ReactMapGL>
      </>
    );
  }
}

Map.propTypes = {
  selectedGasType: PropTypes.string.isRequired,
  showGasStation: PropTypes.func.isRequired,
  toastManager: PropTypes.shape({
    add: PropTypes.func,
  }).isRequired,
};

export default withToastManager(Map);
