var Clay = require('pebble-clay');
var clayConfig = require('./config');
var clay = new Clay(clayConfig);


var messageKeys = require('message_keys');

var message;
var gpx_to_strava = false;
var gpx_to_web = true;

var locationInterval;

var firstlocationOptions = {
  'enableHighAccuracy': true, // default = false (quick and dirty mode), can be true (more accurate but need more power and time)
  'timeout': 60000, //60s timeout to get a good signal
  'maximumAge': 5 // no cache
};
var locationOptions = {
  'enableHighAccuracy': true, // default = false (quick and dirty mode), can be true (more accurate but need more power and time)
  'timeout': 5000, //5s timeout to get a good signal
  'maximumAge': 5 // no cache
};
var geoloc_id;

// Store location in Pebble app local storage
//
function storeLocation(position) {
  var latitude = position.coords.latitude;
  var longitude = position.coords.longitude;
  var timestamp = position.timestamp;
  localStorage.setItem("latitude", latitude);
  localStorage.setItem("longitude", longitude);
  localStorage.setItem("timestamp", timestamp);
  // console.log("Stored location " + position.coords.latitude + ',' + position.coords.longitude);
}

// Get location from Pebble app local storage
//
function getLocation() {
  if (localStorage.getItem("latitude") || localStorage.getItem("longitude") || localStorage.getItem("timestamp")) {
    var la = localStorage.getItem("latitude");
    var lo = localStorage.getItem("longitude");
    var ti = localStorage.getItem("timestamp");
    var co = { "latitude": la, "longitude": lo };
    var pos = { "coords": co, "timestamp": ti };
    // console.log("Stored location " + pos.co.la + ',' + pos.co.lo);
    return pos;
  } else {
    return null;
  }
}

// Calculate the distance from 2 geoloc in degrees.
// IMPORTANT : this is a calculation from 2D projection, altitude is not involved
//
function distance_on_geoid(lat1, lon1, lat2, lon2) {
  // Convert degrees to radians
  lat1 = lat1 * Math.PI / 180.0;
  lon1 = lon1 * Math.PI / 180.0;
  lat2 = lat2 * Math.PI / 180.0;
  lon2 = lon2 * Math.PI / 180.0;
  // radius of earth in metres
  r = 6378100;
  // P
  rho1 = r * Math.cos(lat1);
  z1 = r * Math.sin(lat1);
  x1 = rho1 * Math.cos(lon1);
  y1 = rho1 * Math.sin(lon1);
  // Q
  rho2 = r * Math.cos(lat2);
  z2 = r * Math.sin(lat2);
  x2 = rho2 * Math.cos(lon2);
  y2 = rho2 * Math.sin(lon2);
  // Dot product
  dot = (x1 * x2 + y1 * y2 + z1 * z2);
  cos_theta = dot / (r * r);
  theta = Math.acos(cos_theta);
  // Distance in Metres
  return r * theta;
}

// Calculate speed from 2 geoloc point arrays (with lat,long,timestamp)
//
function speed_from_distance_and_time(p1, p2) {
  dist = distance_on_geoid(p1.coords.latitude, p1.coords.longitude, p2.coords.latitude, p2.coords.longitude);
  // timestamp is in milliseconds
  time_s = (p2.timestamp - p1.timestamp) / 1000.0;
  speed_mps = dist / time_s;
  speed_kph = (speed_mps * 3600.0) / 1000.0;
  return speed_kph;
}

// Get max speed of the run
//
function getMaxSpeed(lastSpeed) {
  oldmax = localStorage.getItem("maxSpeed") || -1;
  if (oldmax < lastSpeed) {
    maxSpeed = lastSpeed
  } else if (oldmax > lastSpeed) {
    maxSpeed = oldmax
  } else {
    maxSpeed = oldmax
  }
  localStorage.setItem("maxSpeed", maxSpeed);
  return maxSpeed
}

// split float number into an array of int (null returned instead of 0 for decimal)
//
function splitFloatNumber(num) {
  const intStr = num.toString().split('.')[0];
  const decimalStr = num.toString().split('.')[1];
  return [Number(intStr), Number(decimalStr)];

}

// Build GPX headers
//
function GPXHeadersBuilder(timestamp, name, type) {
  var headers = '<?xml version="1.0" encoding="UTF-8"?><gpx creator="Pebble with barometer" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd" version="1.1" xmlns="http://www.topografix.com/GPX/1/1"><metadata><time>' + timestamp + '</time></metadata><trk><name>' + name + '</name><type>' + type + '</type><trkseg>';
  var ret = localStorage.setItem("GPX", headers);
  return true;
}

// Build GPX footer
//
function GPXtrkptBuilder(lat, lon, ele, timestamp) {
  var GPX = localStorage.getItem("GPX");
  var trkpt = '<trkpt lat="' + lat + '" lon="' + lon + '"><ele>' + ele + '</ele><time>' + timestamp + '</time></trkpt>';
  localStorage.setItem("GPX", GPX + trkpt);
  return true;
}

// Build GPX footer
//
function GPXfooterBuilder() {
  var GPX = localStorage.getItem("GPX");
  var footer = '</trkseg></trk></gpx>';
  var ret = localStorage.setItem("GPX", GPX + footer);
  //console.log("GPX closed : " + GPX + footer);
  return ret;
}


// Send GPX to Strava profile
// TODO : get authentication creds from settings
function SendToStrava() {
  console.log('--- GPX upload to strava');
  var gpxfile = localStorage.getItem("GPX");
  // need to automate oAUTH
  var bearer = "8a68d5b79f2fb3e00ad3eaa5025253990fbd6a58"
  params = {
    url: "https://www.strava.com/api/v3/uploads",
    method: "POST",
    data: { description: "desc", data_type: "gpx" },
    files: { file: gpxfile },
    authorization: "Bearer " + bearer,
    callback: function () {
      var message = "";
      // what is 'r'
      // what is 'e'
      // what is 'o'
      // what is 'z'
      if (r && console.log(e.status + " - " + e.txt), 201 == e.status) {
        message = "Your activity has been created";
      } else if (400 == e.status) {
        message = "An error has occurred. If you've already uploaded the current activity, please delete it in Strava.";
      } else if (401 == e.status) {
        message = "Error - Unauthorized. Please check your credentials in the settings.", o.setAccessToken("");
      } else {
        try {
          response_json = JSON.parse(e.txt)
          response_json.error ? (r && console.log("error:" + response_json.error), message = response_json.error, o.setAccessToken("")) : response_json.status && (r && console.log("status:" + response_json.status), z = response_json.status)
        } catch (e) {
          console.log("Error log, " + e)
        }
      }
      message && Pebble.showSimpleNotificationOnPebble("Ventoo SE - Strava", message)
    }
  }
  var XHR = new XMLHttpRequest;
  console.log(params.url);
  XHR.open(params.method, params.url, !0);
  var body = "";
  var boundary = Math.random().toString().substring(2);
  XHR.setRequestHeader("content-type", "multipart/form-data; charset=utf-8; boundary=" + boundary)
  XHR.setRequestHeader("Authorization", params.authorization);
  for (var i in params.data) body += "--" + boundary + '\r\nContent-Disposition: form-data; name="' + i + '"\r\n\r\n' + params.data[i] + "\r\n";
  for (var i in params.files) body += "--" + boundary + '\r\nContent-Disposition: form-data; name="' + i + '" ; filename=test.gpx\r\n\r\n' + params.files[i] + "\r\n";
  body += "--" + boundary + "--\r\n"

  XHR.onreadystatechange = function () {
    // what is 'n'
    try {
      4 == XHR.readyState && (n.status = XHR.status, n.txt = XHR.responseText, n.xml = XHR.responseXML, params.callback && params.callback())
    } catch (e) {
      console.error("Error2 loading, ", e)
    }
  }
  XHR.send(body)



  // fetch or Blob or Formdata are not implemented in pebblekitJS
  /*fetch('data:application/gpx+xml;base64,'.btoa(GPX))
      .then(function(value) { return value.blob() })
      .then(
          function(value) {
  var data = new FormData();
  data.append("name", "test");
  data.append("description", "description");
  data.append("data_type", "gpx");
  data.append("file", value, "blob.gpx");

  var xhr = new XMLHttpRequest();
  var url = "https://www.strava.com/api/v3/uploads";
  xhr.withCredentials = true;
  xhr.timeout = 10000; // time in milliseconds

  xhr.open("POST", url, false);
  xhr.setRequestHeader("Authorization", "Bearer 8a68d5b79f2fb3e00ad3eaa5025253990fbd6a58");

  console.log('------GPX / xhr opened with authorization')
  console.log('------array for blob: ' + [GPX])
  xhr.onload = function() {
      console.log('------xhr onload')
      if (xhr.readyState === 4) {
          console.log('------xhr request returned with ' + xhr.status);
          console.log(this.responseText);
          if (xhr.status == 200) {
              //console.log('--> HTTP 200');
              return true;
          } else {
              //console.log('--> HTTP ' + xhr.status);
              return false;
          }
      }
  };

  xhr.send(data);
  },
          function(error) {
              console.log('error')
          }
      )*/
  /* -------------------- */


}


// Build CSV
function CSV(pos) {
  var CSV = localStorage.getItem("CSV");
  var datapoint = pos.timestamp + "," + pos.coords.latitude + "," + pos.coords.longitude + "," + pos.coords.altitude + "," + pos.coords.accuracy + "," + pos.coords.altitudeAccuracy + "," + pos.coords.heading + "," + pos.coords.speed + "\n";

  localStorage.setItem("CSV", CSV + datapoint);

}
// Send CSV to web server (need configuration on serverside)
// TODO : secure it ?
function PostToWeb() {
  console.log('--- GPX upload to custom web server');
  var GPX = localStorage.getItem("GPX");

  var url = "https://jonget.fr/strava/upload.php?name=pebblegpx&type=application/gpx+xml";
  var xhr = new XMLHttpRequest();
  xhr.timeout = 10000; // time in milliseconds

  xhr.open("POST", url, false);

  //console.log('------ CSV / xhr opened')
  xhr.onload = function () {
    //console.log('------xhr onload')
    if (xhr.readyState === 4) {
      //console.log('------xhr request returned with ' + xhr.status);
      //console.log(this.responseText);
      if (xhr.status == 200) {
        //console.log('--> HTTP 200');
        return true;
      } else {
        //console.log('--> HTTP ' + xhr.status);
        return false;
      }
    }
  };

  //send CSV in body
  xhr.send(GPX);

}

// Send location to web server for instant location (no tracking)
// TODO : secure it ?
function instantLocationUpdate(pos) {
  console.log('--- Instant location update');
  // console.log(" location is " + new_pos.coords.latitude + ',' + new_pos.coords.longitude + ' , acc. ' + new_pos.coords.accuracy);

  var url = "https://jonget.fr/find_me/update.php?lat=" + pos.coords.latitude + "&long=" + pos.coords.longitude + "&acc=" + pos.coords.accuracy + "&timestamp=" + pos.timestamp;
  var xhr = new XMLHttpRequest();
  xhr.timeout = 10000; // time in milliseconds

  xhr.open("POST", url);

  //console.log('------ instant / xhr opened')
  xhr.onload = function () {
    //console.log('------xhr onload')
    if (xhr.readyState === 4) {
      //console.log('------xhr request returned with ' + xhr.status);
      //console.log(this.responseText);
      if (xhr.status == 200) {
        //console.log('--> HTTP 200');
        return true;
      } else {
        //console.log('--> HTTP ' + xhr.status);
        return false;
      }
    }
  };

  //send without body
  xhr.send();

}


// Adding leading characters to string for nice displays
//
function padStart(string, max_length, padding) {
  if (string.length > max_length) {
    return string;
  } else {
    var new_str = string;
    for (index = string.length; index < max_length; index++) {
      new_str = "0" + new_str;
    }
    return new_str;
  }
}

// called in case of successful geoloc gathering and sends the coordinate to watch
//
function locationSuccess(new_pos) {
  console.log('--- locationSuccess');
  // console.log(" location is " + new_pos.coords.latitude + ',' + new_pos.coords.longitude + ' , acc. ' + new_pos.coords.accuracy);

  var prev_pos = getLocation();
  storeLocation(new_pos);
  if (prev_pos === null) {
    console.log('--- start building gpx');

    if (gpx_to_strava || gpx_to_web) {
      // Start the GPX file
      GPXHeadersBuilder(new Date(new_pos.timestamp).toISOString(), "test", "18");
    }
  } else {
    //clear watch of new position to avoid overlap
    //navigator.geolocation.clearWatch(geoloc_id);
    //console.log('--- watch geoloc cleared');
    //var speed = speed_from_distance_and_time(prev_pos, new_pos);

    //get speed from geoloc API isntead of calculate it
    // speed is initially in m/s, get it at km/h
    if (new_pos.coords.speed === null) {
      var speed = 0;
    } else {
      var speed = new_pos.coords.speed * 3.6;
    }

    // Prepare display on watch
    // now it's only raw data
    // init strings
    var latitudeString = "";
    var longitudeString = "";
    var accuracyString = "";
    var altitudeString = "";
    var speedString = "";

    //formating for precision and max size
    latitudeString = new_pos.coords.latitude.toString().substring(0, 12);
    longitudeString = new_pos.coords.longitude.toString().substring(0, 12);
    accuracyString = new_pos.coords.accuracy.toString().substring(0, 4);
    //console.log("split num : " + new_pos.coords.altitude);
    altitudeString = splitFloatNumber(new_pos.coords.altitude)[0].toString().substring(0, 5);
    timestampISO = new Date(new_pos.timestamp).toISOString();
    //console.log("split num : " + speed);
    speedString = splitFloatNumber(speed)[0].toString().substring(0, 3); //+ "." + splitFloatNumber(speed)[1].toString().substring(0, 1);

    //console.log("split num : " + getMaxSpeed(speed));
    maxSpeedString = splitFloatNumber(getMaxSpeed(speed))[0].toString().substring(0, 4);

    if (speedString == "NaN") {
      speedString = "---";
    }

    if (gpx_to_strava || gpx_to_web) {
      //add a new datapoint to GPX file
      GPXtrkptBuilder(latitudeString, longitudeString, altitudeString, timestampISO);

    }

    // Build message
    message = "OK";
    var dict = {
      'accuracy': accuracyString,
      'altitude': altitudeString,
      'speed': speedString,
      'max_speed': maxSpeedString,
      'status': message
    };

    // Send the message
    Pebble.sendAppMessage(dict, function () {
      console.log('Message sent successfully: ' + JSON.stringify(dict));
    }, function (e) {
      console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
    });
  }

}

function locationError(err) {

  console.warn('location error (' + err.code + '): ' + err.message);
  /*
  if (gpx_to_web) {

      var CSV = localStorage.getItem("CSV");
      var datapoint = Date.now() + ",location error," + err.code + "," + err.message + ",,,,";

      localStorage.setItem("CSV", CSV + datapoint);
  }*/

}


function get_coordinate() {
  console.log('--- Starting regular getCurrentPosition loop using setInterval at 5 sec');

  navigator.geolocation.getCurrentPosition(locationSuccess, locationError, firstlocationOptions);

  locationInterval = setInterval(function () {
    navigator.geolocation.getCurrentPosition(locationSuccess, locationError, locationOptions);
  }, 1000);

  instantLocationInterval = setInterval(function () {
    navigator.geolocation.getCurrentPosition(instantLocationUpdate, locationError, locationOptions);
  }, 60000);

}

function init() {
  // local storage init,
  // todo : clear only temporary values, not clay config (and do it on exit ?)
  localStorage.clear();
  localStorage.setItem("CSV", "");
  // clear any other var to do
  clearInterval(locationInterval);

}

// Get JS readiness events
Pebble.addEventListener('ready', function (e) {
  console.log('PebbleKit JS is ready');
  // Update Watch on this
  Pebble.sendAppMessage({ 'JSReady': 1 });

  init();
});

// Get AppMessage events
Pebble.addEventListener('appmessage', function (e) {
  // Get the dictionary from the message
  var dict = e.payload;
  //console.log(dict[0].toString());
  switch (dict[0]) {
    case 'get':
      get_coordinate();
      break;
    case 'exit':
      clearInterval(instantLocationInterval);
      clearInterval(locationInterval);
      if (gpx_to_strava || gpx_to_web) {
        //End GPX file
        GPXfooterBuilder();
        if (gpx_to_strava) {
          //send to strava through API
          SendToStrava();
        }
        if (gpx_to_web) {
          // send CSV to web server through API
          PostToWeb();
        }
      }
      // Send the message
      var dict = {
        'status': "KO"
      };
      Pebble.sendAppMessage(dict, function () {
        console.log('Message sent successfully: ' + JSON.stringify(dict));
      }, function (e) {
        console.log('Message (' + JSON.stringify(dict) + ') failed: ' + JSON.stringify(e));
      });

      break;
    default:
      console.log('Sorry. I don\'t understand your request :' + dict[0]);
  }

});