import ElasticsearchService from '../../services/elasticsearch-service.js';
import DynatraceService from '../../services/dynatrace-service.js';
const debug = false;
export default class DynatraceMetricPublisher {

  constructor(config) {
    const esConfig = {
      index: config.index,
      protocol: config.es_protocol,
      host: config.es_host,
      port: config.es_port,
      username: config.es_username,
      password: config.es_password
    }

    this.elasticsearch = new ElasticsearchService(esConfig);

    const dtConfig = {
      token: config.dynatrace_token,
      baseUrl: config.dynatace_base_url
    }

    this.dynatrace = new DynatraceService(dtConfig);

    this.config = config;
  }

  async publish() {
    let query = "";
    query += "logentrytype:dynatraceMetric AND ";
    query += "app:" + this.config.app + " AND ";
    query += "env:" + this.config.env + " AND ";
    query += "uuid:" + this.config.uuid;

    if (debug) console.log("EXECUTING WITH QUERY: " + query);

    // get the last result of a previous run
    let searchResults = [];
    let retry = 0;
    let now = new Date();
    let from = new Date(now);
    let to = new Date(now);
    let year = now.getFullYear();
    let month = now.getMonth() + 2;
    while (searchResults.length < 1 && retry < 3) {
      if (debug) console.log("TRY: " + retry)
      month = month - 1;
      if (month === 0) {
        month = 12;
        year = year - 1;
      }
      try {
        let dataIndex = this.config.index + '-' + year + '.' + (month).toString().padStart(2, '0');
        if (await this.elasticsearch.indexExists(dataIndex)) {
          if (debug) console.log("The index exists: " + dataIndex)
          try {
            searchResults = await this.elasticsearch.search(dataIndex, 1, query, "start:desc");
            if (debug) console.log(JSON.stringify(searchResults));
          } catch (error) {
            // no result found on index checking previous month on next retry
            searchResults = [];
          }
        } else {
          if (debug) console.log("The index does NOT exist: " + dataIndex)
        }

      } catch (error) {
        // error checking if the index exists, should be retried without going back one month
        month = month +1;
      }
      retry++;
    }
    let last;
    if (searchResults && searchResults[0] && searchResults[0]._source && searchResults[0]._source.start) {
      last  = new Date(searchResults[0]._source.start + 1);
    } else {
      last = new Date();
      last.setFullYear(year, month, 0);
      if (debug) {
        console.log("year: " + year);
        console.log("month: " + month);
        console.log("LAST: " + last);
        console.log("LAST day: " + last.getDate());
        console.log("NOW day: " + now.getDate());
      }

      // make sure the current day exists on the year/month we're setting
      if (now.getDate() < last.getDate()){
        last.setDate(now.getDate());
      }
      if (debug) console.log("LAST day: " + last.getDate());
    }

    from.setTime(last);
    // calculate the difference in days
    const ONE_DAY = 1000 * 60 * 60 * 24;
    while (from < now){

      let differenceMs = Math.abs(now - from);
      let daysDiff = differenceMs / ONE_DAY;
      if (debug) console.log("DIFF in DAYS: " + daysDiff);
      if (daysDiff > 1){
        to.setTime(from.valueOf() + ONE_DAY);
      } else {
        to.setTime(now.valueOf());
      }
      if (debug) {
        console.log("#############################################");
        console.log("FROM: " + from);
        console.log("TO  : " + to);
      }

      //do stuff
      let params = [];
      params.push({key: "metricSelector", value: this.config.dynatrace_metric_selector});
      params.push({key: "resolution", value: "1m"});
      params.push({key: "from", value: from.valueOf()});
      params.push({key: "to", value: to.valueOf()});
      params.push({key: "entitySelector", value: this.config.dynatrace_entity_selector});
      let metrics = false;
      try {
        metrics = await this.dynatrace.getMetric(params);
      } catch (error) {
        // retry
        try {
          metrics = await this.dynatrace.getMetric(params);
        } catch (error) {
          console.error("ERROR getting dynatrace metrics in retry for params: " + JSON.stringify(params));
        }
      }
      if (metrics &&
          metrics.result &&
          metrics.result[0] &&
          metrics.result[0].data &&
          metrics.result[0].data[0] &&
          metrics.result[0].data[0].timestamps &&
          metrics.result[0].data[0].values ){

        let tsForIndex = metrics.result[0].data[0].values[0];
        let dateForIndex = new Date(tsForIndex);
        let dataIndex = this.config.index + '-' + dateForIndex.getFullYear() + '.' + (dateForIndex.getMonth() + 1).toString().padStart(2, '0');
        if (! await this.elasticsearch.indexExists(dataIndex)){
          await this.elasticsearch.createIndex(dataIndex);
        }
        let publishPromises = [];
        let dynatraceMetricPublisher = this;
        for (let index = 0; index < metrics.result[0].data[0].timestamps.length; index++) {
          const timestamp = metrics.result[0].data[0].timestamps[index];
          dateForIndex = new Date(timestamp);
          const newDataIndex = this.config.index + '-' + dateForIndex.getFullYear() + '.' + (dateForIndex.getMonth() + 1).toString().padStart(2, '0');
          if (newDataIndex !== dataIndex ){
            dataIndex = newDataIndex;
            if (! await this.elasticsearch.indexExists(dataIndex)){
              await this.elasticsearch.createIndex(dataIndex);
            }
          }
          const value =     metrics.result[0].data[0].values[index];
          if (timestamp <= to.valueOf() && value>-1){
            // do stuff
            const data = {
              uuid: this.config.uuid,
              app: this.config.app,
              env: this.config.env,
              start: timestamp,
              successRate: value
            }

            if (debug) console.log("INDEXING: " + JSON.stringify(data))
            
            publishPromises.push(new Promise(async (resolve) => {
              await dynatraceMetricPublisher.indexResult(data, dataIndex);
              resolve();
            }));

          }
        }
        await Promise.all(publishPromises);
      } else {
        console.error("ERROR getting dynatrace metrics for params: " + JSON.stringify(params));
        if (!metrics.result){
          console.error("RESULT IS missing: metrics.result");
        } else if (!metrics.result[0]){
          console.error("RESULT IS missing: metrics.result[0]");
        } else if (!metrics.result[0].data){
          console.error("RESULT IS missing: metrics.result[0].data");
        } else if (!metrics.result[0].data[0]){
          console.error("RESULT IS missing: metrics.result[0].data[0]");
        } else if (!metrics.result[0].data[0].timestamps){
          console.error("RESULT IS missing: metrics.result[0].data[0].timestamps ARRAY");
          if (!metrics.result[0].data[0].values){
            console.error("RESULT IS missing: metrics.result[0].data[0].values ARRAY");
          }
        } else if (!metrics.result[0].data[0].values){
          console.error("RESULT IS missing: metrics.result[0].data[0].values ARRAY");
        }        
      }
      

      from.setTime(to.valueOf() + 1);
    }

    if (debug) {
      console.log("FROM: " + from.valueOf());
      console.log("TO  : " + to.valueOf());
    } 
  }


  async indexResult(data, dataIndex) {
    let startDate = new Date(data.start);
    let weekday = startDate.getDay();
    let dayminute = (startDate.getHours() * 60) + startDate.getMinutes();
    // let endDate = new Date(data.end);
    try {
      let result = {
        logentrytype: 'dynatraceMetric',
        uuid: data.uuid,
        app: data.app,
        env: data.env,
        start: startDate.getTime(),
        weekday: weekday,
        dayminute: dayminute,
        describesSuccessRate: data.successRate,
      };

      await this.elasticsearch.index(result, dataIndex);
    } catch (error) {
      console.error('Error indexing dynatrace metric in DynatraceMetricPublisher: error: ' + error);
      return null;
    }
  }
}
