class ConsulService {
  constructor(ressourceURL, refresh) {
    this.ressourceURL = ressourceURL;
    this.fetchRessource();
    this.serviceList = $("#service-list");
    this.serviceFilter = $("#service-filter");
    this.serviceFilter.keyup(this.filterService);
    this.refresh = parseInt(refresh);
    this.filterStatus = null;
  }

  fetchRessource() {
    $.ajax({url: "consul_template.json", cache: false, dataType: "json", sourceObject: this, success: function(result){
      consulService.initRessource(result);
    }});
  }

  initRessource(data) {
    this.data = data;
    this.reloadServiceList();
    console.log('Data generated at: ' + data['generated_at']);

    var urlParam = new URL(location.href).searchParams.get('service');
    if (urlParam) {
      var nodes = document.getElementById('service-list').childNodes;
      for(var i in nodes) {
        if($(nodes[i]).find(".service-name").html() == urlParam) {
          var selectedElement = $(nodes[i])
          this.selectService(selectedElement);
          selectedElement.focus()
          break;
        }
      }
    } else {
      this.selectService(document.getElementById('service-list').firstElementChild);
    }

    if(this.refresh > 0) {
      setTimeout(this.fetchRessource, this.refresh * 1000);
    }
  }

  reloadServiceList() {
    for (var serviceName in this.data.services) {
      var service = this.data.services[serviceName];
      var serviceStatus = buildServiceStatus(service);
      var listItem = '<button type="button" onfocus="consulService.onClickServiceName(this)" onclick="consulService.onClickServiceName(this)" value="' + serviceName + '" class="list-group-item list-group-item-action">';
      listItem += '<div class="statuses" style="float:right">'
      var globalStatus = 'dark'
      if (!!serviceStatus['passing']) {
        listItem += '<span class="badge badge-pill badge-success" style="margin-right:10px;">' + serviceStatus['passing'] + '</span>';
      }
      if (!!serviceStatus['warning']) {
        listItem += '<span class="badge badge-pill badge-warning" style="margin-right:10px;">' + serviceStatus['warning'] + '</span>';
        if (globalStatus == 'dark') {
          globalStatus = 'warning'
        }
      }
      if (!!serviceStatus['critical']) {
        listItem += '<span class="badge badge-pill badge-danger" style="margin-right:10px;">' + serviceStatus['critical'] + '</span>';
        globalStatus = 'critical'
      }
      listItem+= ' / <span class="badge badge-pill badge-dark">' + (serviceStatus['total'] || 0) + '</span></div>';
      listItem += '<div class="service-name text-' + globalStatus + '">' + serviceName + '</div>';
      listItem += '<div class="service-tags">'
      for (var i = 0; i < service.tags.length; i++) {
        listItem += '<span title="' + service.tags[i] + '" class="badge badge-pill badge-' + (i%2?'secondary':'info') + '" style="float:right;">' + (service.tags[i]) + '</span> ';
      }
      listItem += '</div>'
      listItem += '</button>';
      this.serviceList.append(listItem);
    }
    resizeWrapper('service-wrapper', 'service-list');
  }

  filterService(e) {
    var filter = new RegExp(e.target.value);
    consulService.serviceList.children('button').each(function (){
      if($(this).html().match(filter)) {
        var ui = $(this).closest( "button" )
        ui.removeClass('d-none');
        ui.addClass('d-block');
      } else {
        var ui = $(this).closest( "button" )
        ui.removeClass('d-block');
        ui.addClass('d-none');
      }
    })
  }

  onClickServiceName(source) {
    this.selectService(source);
    this.updateURL($(source).find(".service-name").html());
  }

  onClickFilter(source) {
    var status = $(source).attr('status');
    this.filterStatus = (this.filterStatus == status) ? null : status;
    this.filterInstances();
  }

  filterInstances() {
    $('.progress-status').each(function() {
      var status = $(this).attr('status');
      if (consulService.filterStatus == null) {
        $(this).removeClass('progress-deactivated');
      } else if(consulService.filterStatus == status) {
        $(this).removeClass('progress-deactivated');
      } else {
        $(this).addClass('progress-deactivated');
      }
    })
    $('#instances-list').children('div').each(function() {
      var status = $(this).attr('status');
      if (consulService.filterStatus == null) {
        $(this).removeClass('d-none');
        $(this).addClass('d-block');
      } else if (consulService.filterStatus == status) {
        $(this).removeClass('d-none');
        $(this).addClass('d-block');
      } else {
        $(this).removeClass('d-block');
        $(this).addClass('d-none');
      }
    })
  }

  updateURL(link) {
    var newUrl = window.location.protocol + "//" + window.location.host + window.location.pathname;
    if (link) {
      newUrl += '?service=' + link
    }
    window.history.pushState({},"",newUrl);
  }

  selectService(source) {
    if (this.selectedService) {
      $(this.selectedService).removeClass('active');
    }
    var serviceName = $(source).find(".service-name").html()
    this.selectedService = source.closest( "button" );
    $(this.selectedService).addClass('active');

    this.displayService(this.data.services[serviceName]);
  }

  displayService(service) {
    $("#service-title").html(service['name']);
    $("#instances-list").html("");

    var serviceStatus = buildServiceStatus(service);

    for (var key in service['instances']) {
      var instance = service['instances'][key];
      var serviceHtml = document.createElement('div');
      serviceHtml.setAttribute('class','list-group-item');

      serviceHtml.appendChild(serviceTitleGenerator(instance));
      serviceHtml.appendChild(tagsGenerator(instance));
      serviceHtml.appendChild(checksStatusGenerator(instance));
      var state = nodeState(instance);
      serviceHtml.setAttribute('status', state);
      $("#instances-list").append(serviceHtml);
    }

    $('#service-progress-passing').css('width', (serviceStatus['passing'] || 0) / serviceStatus['total'] * 100 + '%')
    $('#service-progress-passing').html("passing (" + (serviceStatus['passing'] || 0) + ")")
    $('#service-progress-warning').css('width', (serviceStatus['warning'] || 0) / serviceStatus['total'] * 100 + '%')
    $('#service-progress-warning').html("warning (" + (serviceStatus['warning'] || 0) +")")
    $('#service-progress-critical').css('width', (serviceStatus['critical'] || 0) / serviceStatus['total'] * 100 + '%')
    $('#service-progress-critical').html("critical (" + (serviceStatus['critical'] || 0) + ")")

    resizeWrapper('instances-wrapper', 'instances-list');
    $('#instances-list .list-group-item').resize(resizeAll);
  }
}

function buildServiceStatus(service) {
  var serviceStatus = {};

  for (var key in service['instances']) {
    var instance = service['instances'][key];
    var state = nodeState(instance);

    serviceStatus[state] = (serviceStatus[state] || 0) + 1;
    serviceStatus['total'] = (serviceStatus['total'] || 0) + 1;
  }

  return serviceStatus;
}

function nodeState(instance) {
  status='passing';
  for (var checkKey in instance.checks) {
    switch(instance.checks[checkKey]['status']) {
      case 'passing': break;
      case 'warning': status='warning'; break;
      case 'critical': return 'critical'; break;
    }
  }
  return status;
}

supported_protocols = ['https', 'http', 'sftp', 'ftp', 'ssh', 'telnet']

function serviceTitleGenerator(instance) {
  var protocol = null;
  for (i in supported_protocols) {
    var protoc = supported_protocols[i]
    if (instance.tags.includes(protoc)) {
      protocol = protoc + '://';
      break;
    }
  }

  var htmlTitle = document.createElement('h5');

  var instanceLink = document.createElement('a');
  if (protocol != null) {
    instanceLink.setAttribute('href',  protocol + instance.name + ':' + instance.port);
    instanceLink.setAttribute('target',  '_blank');
  }
  instanceLink.appendChild(document.createTextNode(instance.name + ':' + instance.port));
  htmlTitle.appendChild(instanceLink);

  return htmlTitle;
}

function tagsGenerator(instance) {
  var tags = document.createElement('div');

  tags.className = 'tags';
  tags.appendChild(document.createTextNode("Tags: "));
  tags.appendChild(document.createElement('br'));

  for (var tagKey in instance.tags) {
    var tag = document.createElement('span');
    tag.setAttribute('class', 'badge badge-secondary mx-1');
    tag.appendChild(document.createTextNode(instance.tags[tagKey]));
    tags.appendChild(tag);
  }
  return tags;
}

function checksStatusGenerator(instance) {
  var checks = document.createElement('div');
  checks.className = 'checks';
  checks.appendChild(document.createTextNode("Checks: "));
  checks.appendChild(document.createElement('br'));

  for (var checkKey in instance.checks) {
    checkId = Math.floor(Math.random()*10000);
    switch(instance.checks[checkKey]['status']) {
      case 'passing': var btn = 'btn-success'; break;
      case 'warning': var btn = 'btn-warning'; break;
      case 'critical': var btn = 'btn-danger'; break;
    }
    var check = document.createElement('div');

    var btnCheck = document.createElement('button');
    btnCheck.setAttribute('class','btn ' + btn + ' btn-sm m-1');
    btnCheck.setAttribute('type', 'button');
    btnCheck.setAttribute('data-toggle', 'collapse');
    btnCheck.setAttribute('data-target', '#' + checkId);
    btnCheck.setAttribute('aria-expanded', 'false');

    btnCheck.appendChild(document.createTextNode(instance.checks[checkKey]['name']));

    check.appendChild(btnCheck);

    var collapseCheck = document.createElement('div');
    collapseCheck.setAttribute('class', 'collapse')
    collapseCheck.setAttribute('id', checkId)

    var cardCheck = document.createElement('div');
    cardCheck.setAttribute('class', 'card card-body p-3 m-1 mb-2');

    var notes = document.createElement('table');
    notes.setAttribute('class', 'table table-hover mb-0');

    var dataToDisplay = ['notes', 'output'];
    for (var index in dataToDisplay) {
      var tr = document.createElement('tr');
      var td1 = document.createElement('td');
      var td2 = document.createElement('td');
      var fieldName = dataToDisplay[index].replace(/\b\w/g, l => l.toUpperCase());
      td1.appendChild(document.createTextNode(fieldName + ': '));
      var target = td2
      if (index != 1) {
        target = document.createElement('div');
        target.setAttribute("class", "check-notes")
      } else {
        // Notes are rendered as plain text
        target = document.createElement('pre');
        target.setAttribute("class", "check-output")
      }
      target.appendChild(document.createTextNode(instance.checks[checkKey][dataToDisplay[index]]));
      td2.appendChild(target)
      tr.appendChild(td1);
      tr.appendChild(td2);
      notes.appendChild(tr);
    }

    cardCheck.appendChild(notes);
    collapseCheck.appendChild(cardCheck);
    check.appendChild(collapseCheck);
    checks.appendChild(check)
  }

  return checks;
}

function resizeAll() {
  resizeWrapper('service-wrapper', 'service-list');
  resizeWrapper('instances-wrapper', 'instances-list');
}

function resizeWrapper(wrapperId, wrapped) {
  var size = $(window).height() - $('#' + wrapperId).offset()["top"] - 20;
  $('#' + wrapperId).css("height", size);
}

$( window ).resize(resizeAll);
resizeAll();