<script>
import ResourceTable from '@/components/ResourceTable';
import Loading from '@/components/Loading';
import Tag from '@/components/Tag';
import {
  STATE, NAME, ROLES, VERSION, INTERNAL_EXTERNAL_IP, CPU, RAM, PODS, AGE
} from '@/config/table-headers';
import metricPoller from '@/mixins/metric-poller';

import {
  MANAGEMENT, METRIC, NODE, NORMAN, POD
} from '@/config/types';
import { mapGetters } from 'vuex';
import { allHash } from '@/utils/promise';
import { get } from '@/utils/object';
import { GROUP_RESOURCES, mapPref } from '@/store/prefs';
import { COLUMN_BREAKPOINTS } from '@/components/SortableTable/index.vue';

export default {
  name:       'ListNode',
  components: {
    Loading, ResourceTable, Tag
  },
  mixins: [metricPoller],

  props: {
    schema: {
      type:     Object,
      required: true,
    },
  },

  async fetch() {
    const hash = { kubeNodes: this.$store.dispatch('cluster/findAll', { type: NODE }) };

    const canViewNodePools = this.$store.getters[`management/schemaFor`](MANAGEMENT.NODE_POOL);
    const canViewNodeTemplates = this.$store.getters[`management/schemaFor`](MANAGEMENT.NODE_TEMPLATE);
    const canViewPods = this.$store.getters[`cluster/schemaFor`](POD);

    const canViewNormanNodes = this.$store.getters[`rancher/schemaFor`](NORMAN.NODE);

    if (canViewNormanNodes) {
      // Required for Drain action
      hash.normanNodes = this.$store.dispatch('rancher/findAll', { type: NORMAN.NODE });
    }

    if (canViewNodePools && canViewNodeTemplates) {
      // Managemnet Node's required for kube role and some reousrce states
      hash.mgmtNodes = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE });
      hash.nodePools = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_POOL });
      hash.nodeTemplates = this.$store.dispatch('management/findAll', { type: MANAGEMENT.NODE_TEMPLATE });
    }

    if (canViewPods) {
      // Used for running pods metrics
      hash.pods = this.$store.dispatch('cluster/findAll', { type: POD });
    }

    const res = await allHash(hash);

    this.kubeNodes = res.kubeNodes;
    this.nodePools = res.nodePools || [];
    this.nodeTemplates = res.nodeTemplates || [];

    await this.updateNodePools(res.kubeNodes);
  },

  data() {
    return {
      kubeNodes:     null,
      nodeTemplates: null,
      nodePools:     null,
      headers:          [STATE, NAME, ROLES, VERSION, INTERNAL_EXTERNAL_IP, {
        ...CPU,
        breakpoint: COLUMN_BREAKPOINTS.LAPTOP
      }, {
        ...RAM,
        breakpoint: COLUMN_BREAKPOINTS.LAPTOP
      }, {
        ...PODS,
        breakpoint: COLUMN_BREAKPOINTS.DESKTOP
      }, AGE],
    };
  },

  computed: {
    ...mapGetters(['currentCluster']),
    tableGroup: mapPref(GROUP_RESOURCES),

    clusterNodePools() {
      return this.nodePools?.filter(pool => pool?.spec?.clusterName === this.currentCluster.id) || [];
    },

    clusterNodePoolsMap() {
      return this.clusterNodePools.reduce((res, node) => {
        res[node.id] = node;

        return res;
      }, {});
    },

    hasPools() {
      return !!this.clusterNodePools.length;
    },

    groupBy() {
      if (!this.hasPools) {
        return null;
      }

      return this.tableGroup === 'none' ? '' : 'nodePoolId';
    }

  },

  watch: {
    kubeNodes: {
      deep: true,
      handler(neu, old) {
        this.updateNodePools(neu);
      }
    },
  },

  methods:  {
    async loadMetrics() {
      const schema = this.$store.getters['cluster/schemaFor'](METRIC.NODE);

      if (schema) {
        await this.$store.dispatch('cluster/findAll', {
          type: METRIC.NODE,
          opt:  { force: true }
        });

        this.$forceUpdate();
      }
    },

    updateNodePools(nodes = []) {
      nodes.forEach((node) => {
        const sNode = node.managementNode;

        if (sNode) {
          node.nodePoolId = sNode.spec.nodePoolName?.replace(':', '/') || '' ;
        }
      });
    },

    getNodePoolFromTableGroup(group) {
      return this.getNodePool(group.key);
    },

    getNodeTemplate(nodeTemplateName) {
      const parsedName = nodeTemplateName.replace(':', '/');

      return this.nodeTemplates.find(nt => nt.id === parsedName);
    },

    get,

  }

};
</script>

<template>
  <Loading v-if="$fetchState.pending" />
  <ResourceTable
    v-else
    v-bind="$attrs"
    :schema="schema"
    :headers="headers"
    :rows="[...kubeNodes]"
    :groupable="hasPools"
    :group-by="groupBy"
    group-tooltip="node.list.pool"
    :sub-rows="true"
    v-on="$listeners"
  >
    <template #group-by="{group}">
      <div class="pool-row" :class="{'has-description':clusterNodePoolsMap[group.key] && clusterNodePoolsMap[group.key].nodeTemplate}">
        <div v-trim-whitespace class="group-tab">
          <div v-if="clusterNodePoolsMap[group.key]" class="project-name" v-html="t('resourceTable.groupLabel.nodePool', { name: clusterNodePoolsMap[group.key].spec.hostnamePrefix, count: group.rows.length}, true)">
          </div>
          <div v-else class="project-name" v-html="t('resourceTable.groupLabel.notInANodePool')">
          </div>
          <div v-if="clusterNodePoolsMap[group.key] && clusterNodePoolsMap[group.key].nodeTemplate" class="description text-muted text-small">
            {{ clusterNodePoolsMap[group.key].providerDisplay }} &ndash;  {{ clusterNodePoolsMap[group.key].providerLocation }} / {{ clusterNodePoolsMap[group.key].providerSize }} ({{ clusterNodePoolsMap[group.key].providerName }})
          </div>
        </div>
      </div>
    </template>

    <template #sub-row="{fullColspan, row}">
      <tr class="taints sub-row" :class="{'empty-taints': !row.spec.taints || !row.spec.taints.length}">
        <template v-if="row.spec.taints && row.spec.taints.length">
          <td>&nbsp;</td>
          <td>&nbsp;</td>
          <td :colspan="fullColspan-2">
            {{ t('node.list.nodeTaint') }}:
            <Tag v-for="taint in row.spec.taints" :key="taint.key + taint.value + taint.effect" class="mr-5">
              {{ taint.key }}={{ taint.value }}:{{ taint.effect }}
            </Tag>
          </td>
        </template>
        <td v-else :colspan="fullColspan">
&nbsp;
        </td>
      </tr>
    </template>
  </ResourceTable>
</template>

<style lang='scss' scoped>
.pool-row {
  display: flex;
  justify-content: space-between;

  .project-name {
    line-height: 30px;
  }

  &.has-description {
    .right {
      margin-top: 5px;
    }
    .group-tab {
      &, &::after {
        height: 50px;
      }

      &::after {
        right: -20px;
      }

      .description {
        margin-top: -20px;
      }
    }
  }

  BUTTON {
     line-height: 1em;
  }
}

.taints {
  td {
    padding-top:0;
    .tag {
      margin-right: 5px
    }
  }
  &.empty-taints {
    // No taints... so hide sub-row (but not bottom-border)
    height: 0;
    line-height: 0;
    td {
      padding: 0;
    }
  }
}

</style>
