<!--
  @component Cluster Per Node Overview component; renders current state of ONE metric for ALL nodes

  Properties:
  - `ccconfig Object?`: The ClusterCockpit Config Context [Default: null]
  - `cluster String`: The cluster to show status information for
  - `selectedMetric String?`: The selectedMetric input [Default: ""]
  - `hostnameFilter String?`: The active hostname filter [Default: ""]
  - `nodeStateFilter String?`: The active nodeState filter [Default: ""]
  - `from Date?`: The selected "from" date [Default: null]
  - `to Date?`: The selected "to" date [Default: null]
  - `globalMetrics [Obj]`: Includes the backend supplied availabilities for cluster and subCluster
-->

 <script>
  import { queryStore, gql, getContextClient } from "@urql/svelte";
  import { Row, Col, Card, CardHeader, CardBody, Spinner, Badge } from "@sveltestrap/sveltestrap";
  import { checkMetricAvailability } from "../generic/utils.js";
  import MetricPlot from "../generic/plots/MetricPlot.svelte";

  /* Svelte 5 Props */
  let {
    ccconfig = null,
    cluster = "",
    selectedMetric = "",
    hostnameFilter = "",
    nodeStateFilter = "",
    from = null,
    to = null,
    globalMetrics
  } = $props();

  /* Const Init */
  const client = getContextClient();
  // Node State Colors
  const stateColors = {
    allocated: 'success',
    reserved: 'info',
    idle: 'primary',
    mixed: 'warning',
    down: 'danger',
    unknown: 'dark',
    notindb: 'secondary'
  }

  /* Derived */
  const nodesQuery = $derived(queryStore({
    client: client,
    query: gql`
      query ($cluster: String!, $metrics: [String!], $from: Time!, $to: Time!) {
        nodeMetrics(
          cluster: $cluster
          metrics: $metrics
          from: $from
          to: $to
        ) {
          host
          nodeState
          subCluster
          metrics {
            name
            scope
            metric {
              timestep
              unit {
                base
                prefix
              }
              series {
                statistics {
                  min
                  avg
                  max
                }
                data
              }
            }
          }
        }
      }
    `,
    variables: {
      cluster: cluster,
      metrics: [selectedMetric],
      from: from,
      to: to,
    },
  }));

  const notConfigured = $derived(checkMetricAvailability(globalMetrics, selectedMetric, cluster) == "none");
  const mappedData = $derived(handleQueryData($nodesQuery?.data));
  const filteredData = $derived(mappedData.filter((h) => {
    if (hostnameFilter) {
      if (nodeStateFilter == 'all') return h.host.includes(hostnameFilter)
      else return (h.host.includes(hostnameFilter) && h.nodeState == nodeStateFilter)
    } else {
      if (nodeStateFilter == 'all') return true
      else return h.nodeState == nodeStateFilter
    }
  }));

  /* Functions */
  function handleQueryData(queryData) {
    let rawData = []
    if (queryData) { 
      rawData = queryData.nodeMetrics.filter((h) => {
        if (h.subCluster !== '') { // Exclude nodes with empty subCluster field
          return h.metrics.some(
            (m) =>  m?.name == selectedMetric && m.scope == "node",
          )
        };
      });
    };

    let pendingMapped = [];
    if (rawData.length > 0) {
      pendingMapped = rawData.map((h) => ({
        host: h.host,
        nodeState: h?.nodeState || 'notindb',
        subCluster: h.subCluster,
        data: h.metrics.filter(
          (m) => m?.name == selectedMetric && m.scope == "node",
        ),
        availability: checkMetricAvailability(globalMetrics, selectedMetric, cluster, h.subCluster),
      }))
      .sort((a, b) => a.host.localeCompare(b.host))
    }

    return pendingMapped;
  }
</script>

{#if $nodesQuery.error}
  <Row>
    <Col>
      <Card body color="danger">{$nodesQuery.error.message}</Card>
    </Col>
  </Row>
{:else if $nodesQuery.fetching }
  <Row>
    <Col>
      <Spinner />
    </Col>
  </Row>
{:else if filteredData?.length > 0}
  <!-- PlotGrid flattened into this component -->
  <Row cols={{ xs: 1, sm: 2, md: 3, lg: ccconfig.plotConfiguration_plotsPerRow}}>
    {#key selectedMetric}
      {#each filteredData as item (item.host)}
        <Col class="px-1">
          <div class="d-flex align-items-baseline">
            <h4 style="width: 100%; text-align: center;">
              <a
                style="display: block;padding-top: 15px;"
                href="/monitoring/node/{cluster}/{item.host}"
                >{item.host} ({item.subCluster})</a
              >
            </h4>
            <span style="margin-right: 0.5rem;">
              <Badge color={stateColors[item?.nodeState || 'notindb']}>
                State: {item?.nodeState ? item.nodeState.charAt(0).toUpperCase() + item.nodeState.slice(1) : 'Not in DB'}
              </Badge>
            </span>
          </div>
          {#if item?.availability == "disabled"}
            <Card color="info">
              <CardHeader class="mb-0">
                <b>Disabled Metric</b>
              </CardHeader>
              <CardBody>
                <p>No dataset(s) returned for <b>{selectedMetric}</b></p>
                <p class="mb-1">Metric has been disabled for subcluster <b>{item.subCluster}</b>.</p>
              </CardBody>
            </Card>
          {:else if item?.data}
            <!-- "Empty Series"-Warning included in MetricPlot-Component   -->
            <!-- #key: X-axis keeps last selected timerange otherwise -->
            {#key item?.data[0]?.metric?.series[0]?.data?.length}
              <MetricPlot
                timestep={item?.data[0]?.metric?.timestep || 60}
                series={item?.data[0]?.metric?.series || []}
                metric={item?.data[0]?.name || 'unknown'}
                {cluster}
                subCluster={item?.subCluster || 'unknown'}
                forNode
                enableFlip
              />
            {/key}
          {:else}
            <!-- Should Not Appear -->
            <Card color="warning">
              <CardHeader class="mb-0">
                <b>Missing Metric</b>
              </CardHeader>
              <CardBody>
                <p>No dataset(s) returned for <b>{selectedMetric}</b>.</p>
                <p class="mb-1">Metric was not found in metric store for host <b>{item.host}</b>.</p>
              </CardBody>
            </Card>
          {/if}
        </Col>
      {/each}
    {/key}
  </Row>
{:else if hostnameFilter || nodeStateFilter != 'all'}
  <Row class="mx-1">
    <Card class="px-0">
      <CardHeader>
        <b>Empty Filter Return</b>
      </CardHeader>
      <CardBody>
        <p>No datasets returned for <b>{selectedMetric}</b>.</p>
        <p class="mb-1">Hostname filter and/or host state filter returned no matches.</p>
      </CardBody>
    </Card>
  </Row>
{:else if notConfigured}
  <Row class="mx-1">
    <Card class="px-0" color="light">
      <CardHeader>
        <b>Metric not configured</b>
      </CardHeader>
      <CardBody>
        <p>No datasets returned for <b>{selectedMetric}</b>.</p>
        <p class="mb-1">Metric is not configured for cluster <b>{cluster}</b>.</p>
      </CardBody>
    </Card>
  </Row>
{:else}
  <Row class="mx-1">
    <Card class="px-0" color="warning">
      <CardHeader>
        <b>Missing Metric</b>
      </CardHeader>
      <CardBody>
        <p>No datasets returned for <b>{selectedMetric}</b>.</p>
        <p class="mb-1">Metric was not found in metric store for cluster <b>{cluster}</b>.</p>
      </CardBody>
    </Card>
  </Row>
{/if}