"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.topPod = topPod;
exports.topContainer = topContainer;

var _core = require("@kui-shell/core");

var _pluginKubectl = require("@kui-shell/plugin-kubectl");

var _getNodeData = require("./get-node-data");

/*
 * Copyright 2019 IBM Corporation
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
var __awaiter = void 0 && (void 0).__awaiter || function (thisArg, _arguments, P, generator) {
  function adopt(value) {
    return value instanceof P ? value : new P(function (resolve) {
      resolve(value);
    });
  }

  return new (P || (P = Promise))(function (resolve, reject) {
    function fulfilled(value) {
      try {
        step(generator.next(value));
      } catch (e) {
        reject(e);
      }
    }

    function rejected(value) {
      try {
        step(generator["throw"](value));
      } catch (e) {
        reject(e);
      }
    }

    function step(result) {
      result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected);
    }

    step((generator = generator.apply(thisArg, _arguments || [])).next());
  });
};

// import { parseAsTime, parseAsSize } from '../lib/parse'
const strings = (0, _core.i18n)('plugin-kubectl', 'view-utilization-table');
/**
 * @return an indicator of whether a given pod name is in a given
 * node, subject to any namespace or label filters in the given args
 *
 */

function getPodsInNode(args, forNode) {
  return __awaiter(this, void 0, void 0, function* () {
    const {
      content
    } = yield args.REPL.rexec(`kubectl get pods -o json -n ${yield (0, _pluginKubectl.getNamespace)(args)} ${(0, _pluginKubectl.getLabelForArgv)(args)}`);
    const empty = {};

    if (content && content.items) {
      return content.items.filter(_ => _.spec.nodeName === forNode).map(_ => _.metadata.name) // name versus fqn?
      .reduce((M, fqn) => {
        M[fqn] = true;
        return M;
      }, empty);
    } else {
      return empty;
    }
  });
}

function withAllNamespaces(args) {
  const args2 = Object.assign({}, args);
  args2.command = args2.command + ' -A';
  args2.argv = args2.argv.slice(0).concat(['-A']);
  return args2;
}

const lighterText = ['processing-text', 'semi-bold'];

function addRow(forThisNS, key, cpu, mem, css, formatAs = 'share') {
  const row = JSON.parse(JSON.stringify(forThisNS.body[0]));
  row.onclick = false;
  row.rowKey = key;
  row.name = strings(key);
  row.attributes[0].value = formatAs === 'share' ? _pluginKubectl.Parser.formatAsCpu(cpu) : (100 * cpu).toFixed(0) + '%';
  row.attributes[1].value = formatAs === 'share' ? _pluginKubectl.Parser.formatAsBytes(mem) : (100 * mem).toFixed(0) + '%';

  if (css) {
    row.css = css;
    row.attributes[0].css = css.join(' ');
    row.attributes[1].css = css.join(' ');
  }

  forThisNS.body.push(row);
}

function addAllNSRow(args, forThisNS, forAllNS) {
  return __awaiter(this, void 0, void 0, function* () {
    if (forThisNS.body && forThisNS.body.length > 0) {
      const cpuTotal = forThisNS.body.reduce((total, row) => total + _pluginKubectl.Parser.cpuShare(row.attributes[0].value), 0);
      const memTotal = forThisNS.body.reduce((total, row) => total + _pluginKubectl.Parser.memShare(row.attributes[1].value), 0);
      addRow(forThisNS, 'Total', cpuTotal, memTotal);

      if (forAllNS.body && forAllNS.body.length > 0) {
        const thisNS = yield (0, _pluginKubectl.getNamespace)(args);
        const otherNS = forAllNS.body.filter(_ => _.name !== thisNS);
        const cpuTotal = otherNS.reduce((total, row) => total + _pluginKubectl.Parser.cpuShare(row.attributes[1].value), 0);
        const memTotal = otherNS.reduce((total, row) => total + _pluginKubectl.Parser.memShare(row.attributes[2].value), 0);
        addRow(forThisNS, 'Other Namespaces', cpuTotal, memTotal, lighterText);
      }
    }

    return forThisNS;
  });
}
/**
 * Command handler for `kubectl top pod` default handler
 *
 */


function getPodDataForAllNodes(args, top) {
  return __awaiter(this, void 0, void 0, function* () {
    if ((0, _pluginKubectl.isForAllNamespaces)(args.parsedOptions) || args.parsedOptions.containers) {
      return top(args);
    } else {
      const [forThisNS, forAllNS] = yield Promise.all([top(args), top(withAllNamespaces(args))]);
      return addAllNSRow(args, forThisNS, forAllNS);
    }
  });
}
/**
 * Command handler for `kubectl top pod --node <node>`
 *
 */


function getPodDataForOneNode(args, top) {
  return __awaiter(this, void 0, void 0, function* () {
    const forNode = args.parsedOptions.node; // strip off the --node <node> option

    (0, _getNodeData.strip)(args, '--node', 1); // 1 means --node takes 1 arg

    if ((0, _pluginKubectl.isForAllNamespaces)(args.parsedOptions) || args.parsedOptions.containers) {
      const [podTable, pods] = yield Promise.all([top(args), getPodsInNode(args, forNode)]);

      if (podTable.body) {
        podTable.body = podTable.body.filter(row => pods[row.name]);
      }

      return podTable;
    } else {
      const [podTable, pods, podTableInAllNS] = yield Promise.all([top(args), getPodsInNode(args, forNode), top(withAllNamespaces(args))]);

      if (podTable.body) {
        podTable.body = podTable.body.filter(row => pods[row.name]);
      }

      if (podTableInAllNS.body) {
        podTableInAllNS.body = podTableInAllNS.body.filter(row => pods[row.attributes[0].value]);
      }

      return addAllNSRow(args, podTable, podTableInAllNS);
    }
  });
}
/**
 * Command handler for `kubectl top pod` (overrides built-in functionality)
 *
 */


function topPod(args, top) {
  return __awaiter(this, void 0, void 0, function* () {
    const overheads = (0, _getNodeData.getSystemOverhead)(args, args.parsedOptions.node); // without a --node <node> filter, we use the underlying `top pod` impl

    const table = !args.parsedOptions.node ? yield getPodDataForAllNodes(args, top) : yield getPodDataForOneNode(args, top);

    if (!(0, _core.isTable)(table)) {
      return table;
    } else if (table.body.length === 0) {
      throw new Error(strings('No pods found'));
    }

    const ns = yield (0, _pluginKubectl.getNamespace)(args);
    table.body.forEach(row => {
      // don't need to filter by node: ${args.parsedOptions.node ? `--node ${args.REPL.encodeComponent(args.parsedOptions.node)}` : ''}
      if (row.onclick) {
        row.onclick = `kubectl top container ${args.REPL.encodeComponent(row.name)} -n ${ns} ${(0, _pluginKubectl.getLabelForArgv)(args)}`;
        row.onclickSilence = false;
      }
    });
    const {
      cpuOverhead,
      memOverhead
      /* , cpuCapacity, memCapacity */

    } = yield overheads;
    addRow(table, 'System Overheads', cpuOverhead, memOverhead, lighterText);
    const totalRow = table.body.find(_ => _.rowKey === 'Total');
    const otherNSRow = table.body.find(_ => _.rowKey === 'Other Namespaces');

    if (totalRow && otherNSRow) {
      const totalCPU = _pluginKubectl.Parser.cpuShare(totalRow.attributes[0].value) + _pluginKubectl.Parser.cpuShare(otherNSRow.attributes[0].value) + cpuOverhead;
      const totalMem = _pluginKubectl.Parser.memShare(totalRow.attributes[1].value) + _pluginKubectl.Parser.memShare(otherNSRow.attributes[1].value) + memOverhead; // addRow(table, strings('Free Capacity'), 1 - totalCPU / cpuCapacity, 1 - totalMem / memCapacity, lighterText, 'percent')

      addRow(table, strings('Overall Total'), totalCPU, totalMem, lighterText);
    }

    return table;
  });
}
/**
 * Command handler for `kubectl top container`
 *
 */


function topContainer(args) {
  return __awaiter(this, void 0, void 0, function* () {
    const cmd = args.command.replace('top container', 'top pod').replace(/(-A|--all-namespaces)/, '') + ' --containers';
    const allContainers = yield args.REPL.qexec(cmd); // filter for the given pod name

    const pod = args.argvNoOptions[args.argvNoOptions.indexOf('container') + 1];

    if (allContainers.body) {
      allContainers.body = allContainers.body.filter(_ => _.name === pod);
      allContainers.body.forEach(row => {
        row.onclick = `kubectl get pod ${args.REPL.encodeComponent(row.name)} -o yaml`;
      });
    }

    return allContainers;
  });
}