const _ = require('underscore');
const Backbone = require('backbone');
const geolocation = require('geolocation');
const TimeFormat = require('hh-mm-ss');

const { distance } = require('./libs/utils');

const NodeGeocoder = require('node-geocoder');

// const locationData = require('./location-data.json');

const LocationModel = Backbone.Model.extend({
  'defaults': {

    // defaults go here - "children" may be contained here
  },
  'tick': function() {
    const p = locationData[this.pos];
    const now = new Date();

    console.log(p);
    const location = { 'latitude': p.lat, 'longitude': p.lng, 'timestamp': now.getTime() };
    this.processPosition(location);

    this.timerID = setTimeout(
      () => {
        this.pos++;
        this.tick();
      },
      p.time
    );
  },
  'initialize': function() {
    // this.listenTo(this, 'change sync reset', this.onChange);

    const geoOptions = {
      'maximumAge': 5 * 60 * 1000,
      'timeout': 10 * 1000
    };

    this.pos = 0;
    this.moveTimer = 0;

    geolocation.options = geoOptions;

    geolocation.on('error', function(err) {
      console.warn('Geolocation error');
      console.error(err);
    });

    geolocation.on('change', function( position) {
      console.log('Location update');
      const location = { 'latitude': position.coords.latitude, 'longitude': position.coords.longitude, 'timestamp': position.timestamp };
      this.processPosition(location);

    //  this.set('location', location);
    }.bind(this));

     this.watcher = geolocation.createWatcher();

    this.listenTo(this, 'change:location', this.onChange);
    // this.tick();
  },
  'onChange': function() {
    console.log('>> Location updated');
    console.log(JSON.stringify(this.get('location')));
  },
  'processPosition': function(pos) {
    console.log('processPosition');
    const { latitude, longitude, timestamp } = pos;

    // const current = this.get('location');
    const current = this.toJSON();
    // console.log('># current', current);
    const options = {
      'provider': 'google',

      // Optional depending on the providers
      'httpAdapter': 'https', // Default
      'apiKey': 'AIzaSyA7oGP6QS28tTwtT6UzA7hzh0b3MWwMYB8', // for Mapquest, OpenCage, Google Premier
      'formatter': null // 'gpx', 'string', ...
    };
    const geocoder = NodeGeocoder(options);

    const homeDistance = distance(55.942673, -4.556334, latitude, longitude);
    const workDistance = distance(55.861939, -4.259338, latitude, longitude);
    const atHome = (homeDistance < 0.10);
    const atWork = (workDistance < 0.10);
    const atHomeOrWork = (atHome || atWork);
    const latlong = { 'lat':latitude, 'lon':longitude };
    const ll = `${latitude},${longitude}`;
    const llFixed = `${Number.parseFloat(latitude).toFixed(3)},${Number.parseFloat(longitude).toFixed(3)}`;
    const llSix = `${Number.parseFloat(latitude).toFixed(6)},${Number.parseFloat(longitude).toFixed(6)}`;
    const llShort = `${Number.parseFloat(latitude).toFixed(1)},${Number.parseFloat(longitude).toFixed(1)}`;
    const moving = true;

    const newLocation = { homeDistance, workDistance, latitude, longitude, atHome, atWork, atHomeOrWork, timestamp, ll, llFixed, llSix, llShort, moving, 'city' : '', 'cityCC':'' };

    // console.log('>> NewLocation', JSON.stringify(newLocation));
    //  const distanceFromLast = distance(current.latitude, current.longitude, latitude, longitude);

    if (!_.has(current, 'atHomeOrWork')) {
      console.info('>> Location:geocoder request');
      geocoder.reverse(latlong)
        .then(function(res) {
          console.log(JSON.stringify(res));
          newLocation.city = res[0].city;
          newLocation.cityCC = `${res[0].city},${res[0].countryCode}`;
          newLocation.address = res[0].formattedAddress;
          // this.set('location', newLocation);
          newLocation.lastGeocode = { 'lat':latitude, 'lng':longitude, 'timestamp':timestamp };
          this.set( newLocation);
          // this.set('moving', moving);
          // this.set('lastGeocode', { 'lat':latitude, 'lng':longitude, 'timestamp':timestamp });
          console.log('### location', this);
        }.bind(this))
        .catch(function(err) {
          console.error(err);
          this.set('location', newLocation);
        });
    }
    else {
      newLocation.city = current.city;
      const currentTime = new Date().getTime();
      const distanceFromLast = distance(current.latitude, current.longitude, latitude, longitude);
      const lastGeocode = this.get('lastGeocode');
      const distanceFromLastGeocode = distance(lastGeocode.lat, lastGeocode.lng, latitude, longitude);

      console.log('>> distance from last record', distanceFromLast);
      // console.log('>> distanceFromLastGeocode', distanceFromLastGeocode, TimeFormat.fromMs(timestamp - lastGeocode.timestamp, 'hh:mm:ss'));
      console.log('>> distanceFromLastGeocode', distanceFromLastGeocode, TimeFormat.fromMs(currentTime - lastGeocode.timestamp, 'hh:mm:ss'));
      // console.log(`(currentTime:${currentTime}, timestamp:${timestamp}, lastGeocode.timestamp:${lastGeocode.timestamp})`);
      // console.log('(currentTime - current.timestamp > 900000) ', (currentTime - current.timestamp > 900000));
      // if ((distanceFromLast > 0.5 && distanceFromLast < 2.0) || (timestamp - current.timestamp > 900000)) {
      if ((distanceFromLast > 0.5 && distanceFromLast < 2.0) || ((currentTime - current.timestamp > 900000) && (currentTime - lastGeocode.timestamp < 1.8e+6))) {
        // dont bother re geocoding
        console.log('Slightly moved from previous');
        // this.set('location', newLocation);
        // this.set('moving', moving);
        this.set( newLocation);
      }
      else if (distanceFromLastGeocode >= 2.0 || (currentTime - lastGeocode.timestamp >= 1.8e+6) ) {
        console.log('Moved from previous', (currentTime - lastGeocode.timestamp >= 1.8e+6));
        console.info('>> Location:geocoder request');
        geocoder.reverse(latlong)
          .then(function(res) {
            newLocation.city = res[0].city;
            newLocation.cityCC = `${res[0].city},${res[0].countryCode}`;
            newLocation.address = res[0].formattedAddress;
            console.log('!!! Setting location...');
            //            this.set('location', newLocation);
            //            this.set('lastGeocode', { 'lat':latitude, 'lng':longitude, 'timestamp':timestamp });
            //            this.set('moving', moving);
            newLocation.lastGeocode = { 'lat':latitude, 'lng':longitude, 'timestamp':timestamp };
            this.set( newLocation);
            console.log(this);
          }.bind(this))
          .catch(function(err) {
            console.error(err);
            this.set( newLocation);
          });
      }
    }

    clearTimeout(this.moveTimer);
    this.moveTimer = setTimeout(
      () => {
        console.log('>>>> STOPPED MOVING');
        //        const location = this.get('location');
        //        location.moving = false;
        this.set('moving', false);
        console.log(this);
      },
      30000
    );
  }

});

module.exports = { LocationModel };

// https://www.npmjs.com/package/node-geocoder
