<template>
  <div class="page">
    <section class="card hero glass">
      <div class="hero-left">
        <p class="eyebrow">Titan Lab</p>
        <h1>Overview</h1>
        <p class="lede">
          Titan Lab is a 26-node homelab with a production mindset. Atlas is its Kubernetes cluster that runs user and dev
          services. Oceanus is a dedicated SUI validator host. Underlying components such as Theia, the bastion, and Tethys, the link between 
          Atlas and Oceanus underpin the lab. Membership grants the following services below.
        </p>
        <div class="bullets">
          <div :class="['pill', 'mono', atlasPillClass]">Atlas: flux-managed k3s</div>
          <div :class="['pill', 'mono', oceanusPillClass]">Oceanus: SUI validator</div>
        </div>
        <div class="live-status">
          <div v-if="error" class="status">{{ error }}</div>
          <div v-else class="status mono">
            {{ loading ? "Loading..." : labStatus?.connected ? "Live data connected" : "Live data unavailable" }}
          </div>
        </div>
      </div>
      <div class="availability">
        <div class="availability-grid">
          <div class="availability-panel">
            <div class="panel-title">
              <h3>Atlas</h3>
              <span class="pill mono">k3s cluster</span>
            </div>
            <iframe
              src="https://metrics.bstein.dev/d-solo/atlas-overview/atlas-overview?from=now-24h&to=now&refresh=1m&theme=dark&panelId=27&__feature.dashboardSceneSolo"
              width="100%"
              height="180"
              frameborder="0"
            ></iframe>
          </div>
          <div class="availability-panel">
            <div class="panel-title">
              <h3>Oceanus</h3>
              <span class="pill mono">dedicated host</span>
            </div>
            <div class="placeholder">Loading Oceanus Availability...</div>
          </div>
        </div>
      </div>
    </section>

    <MetricRow :items="metricItems" />

    <section class="card">
      <div class="section-head">
        <h2>Service Grid</h2>
        <span class="pill mono">ai + comms + storage + streaming + development</span>
      </div>
      <ServiceGrid :services="displayServices" />
    </section>

    <section class="grid two">
      <MermaidCard
        title="Atlas layout"
        description="Control plane, workers, accelerators, and edge assets."
        :diagram="hardwareDiagram"
        card-id="hardware-home"
      />
      <MermaidCard
        title="Build + deploy flow"
        description="Gitea to Jenkins to Harbor to Flux."
        :diagram="pipelineDiagram"
        card-id="pipeline-home"
      />
      <MermaidCard
        title="Ingress flow"
        description="DNS to Traefik to workloads backed by Longhorn."
        :diagram="networkDiagram"
        card-id="network-home"
      />
    </section>
  </div>
</template>

<script setup>
import { computed } from "vue";
import MetricRow from "../components/MetricRow.vue";
import ServiceGrid from "../components/ServiceGrid.vue";
import MermaidCard from "../components/MermaidCard.vue";
import { buildHardwareDiagram, buildNetworkDiagram, buildPipelineDiagram, fallbackServices } from "../data/sample.js";

const props = defineProps({
  labData: Object,
  labStatus: Object,
  serviceData: Object,
  networkData: Object,
  metricsData: Object,
  loading: Boolean,
  error: String,
});

const atlasPillClass = computed(() => (props.labStatus?.atlas?.up ? "pill-ok" : "pill-bad"));
const oceanusPillClass = computed(() => (props.labStatus?.oceanus?.up ? "pill-ok" : "pill-bad"));

const metricItems = computed(() => {
  const items = props.metricsData?.items?.length
    ? props.metricsData.items
    : [
    { label: "Lab nodes", value: "26", note: "Workers: 8 rpi5s, 8 rpi4s, 2 jetsons,\n\t\t\t\t 1 minipc\nControl plane: 3 rpi5\nDedicated Hosts: oceanus, titan-db,\n\t\t\t\t\t\t\t\t tethys, theia" },
    { label: "CPU cores", value: "142", note: "32 arm64 cores @ 1.5Ghz\n12 arm64 cores @ 1.9Ghz\n52 arm64 cores @ 2.4Ghz\n10 amd64 cores @ 5.00Ghz\n12 amd64 cores @ 4.67Ghz\n24 amd64 cores @ 4.04Ghz" },
    {
      label: "Memory",
      value: "552 GB",
      note: "64GB  Raspberry Pi 4\n104GB Raspberry Pi 5\n32GB  NVIDIA Jetson Xavier\n352GB AMD64 Chipsets",
    },
    { label: "Storage", value: "80 TB", note: "astreae: 32GB/4xRPI4\nasteria: 48GB/4xRPI4" },
    ];
  return items.map((item) => ({
    ...item,
    note: item.note ? item.note.replaceAll("\t", "    ") : "",
  }));
});

const displayServices = computed(() => {
  const services = props.serviceData?.services || fallbackServices().services;
  return services.map((svc) => ({
    ...svc,
    icon: svc.icon || pickIcon(svc.name),
  }));
});

const hardwareDiagram = computed(() => buildHardwareDiagram(props.labData || {}));
const networkDiagram = computed(() => buildNetworkDiagram(props.networkData || {}));
const pipelineDiagram = computed(() => buildPipelineDiagram());

/**
 * Pick a friendly emoji icon for a service name.
 *
 * WHY: the service grid should stay readable even when upstream service data
 * omits a custom icon, so the default icon needs to be deterministic.
 *
 * @param {string} name - Service display name.
 * @returns {string} Emoji used in the service grid card.
 */
function pickIcon(name) {
  const h = name.toLowerCase();
  if (h.includes("nextcloud")) return "☁️";
  if (h.includes("jellyfin")) return "🎞️";
  if (h.includes("matrix")) return "🗨️";
  if (h.includes("element")) return "🧩";
  if (h.includes("livekit")) return "🎥";
  if (h.includes("coturn") || h.includes("turn")) return "📞";
  if (h.includes("mail")) return "📮";
  if (h.includes("vaultwarden")) return "🔒";
  if (h.includes("vault")) return "🔑";
  if (h.includes("gitea")) return "📚";
  if (h.includes("jenkins")) return "🧰";
  if (h.includes("harbor")) return "📦";
  if (h.includes("flux")) return "🔄";
  if (h.includes("monero")) return "⛏️";
  if (h.includes("sui")) return "💠";
  if (h.includes("keycloak")) return "🛡️";
  if (h.includes("translation")) return "🌐";
  if (h.includes("grafana")) return "📈";
  if (h.includes("pegasus")) return "🚀";
  if (h.includes("ai chat")) return "💬";
  if (h.includes("ai image") || h.includes("vision")) return "🖼️";
  if (h.includes("ai speech")) return "🎙️";
  return "🛰️";
}
</script>

<style scoped>
.page {
  max-width: 1200px;
  margin: 0 auto;
  padding: 32px 22px 72px;
}

.hero {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 18px;
  margin-bottom: 12px;
}

.hero-left {
  display: flex;
  flex-direction: column;
}

.live-status {
  margin-top: auto;
  padding-top: 12px;
}

.eyebrow {
  text-transform: uppercase;
  letter-spacing: 0.08em;
  color: var(--text-muted);
  margin: 0 0 6px;
  font-size: 13px;
}

h1 {
  margin: 0 0 6px;
  font-size: 32px;
}

.lede {
  margin: 0 0 12px;
  color: var(--text-muted);
  max-width: 640px;
}

.bullets {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin: 10px 0 12px;
}

.cta-row {
  display: flex;
  gap: 10px;
  flex-wrap: wrap;
  margin-bottom: 10px;
}

.status {
  color: var(--text-muted);
}

.pill-ok {
  border-color: rgba(0, 229, 197, 0.45);
  color: var(--accent-cyan);
}

.pill-bad {
  border-color: rgba(255, 79, 147, 0.45);
  color: var(--accent-rose);
}

.availability {
  border: 1px solid rgba(255, 255, 255, 0.1);
  border-radius: var(--radius);
  padding: 10px;
  background: rgba(255, 255, 255, 0.03);
}

.availability-grid {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 10px;
}

.availability-panel iframe {
  border: 1px solid rgba(255, 255, 255, 0.08);
  border-radius: var(--radius-sm);
}

.placeholder {
  border: 1px dashed rgba(255, 255, 255, 0.2);
  border-radius: var(--radius-sm);
  padding: 12px;
  color: var(--text-muted);
  text-align: center;
  min-height: 180px;
  display: grid;
  place-items: center;
}

.section-head {
  display: flex;
  align-items: center;
  justify-content: space-between;
  margin-bottom: 10px;
}

@media (max-width: 900px) {
  .hero {
    grid-template-columns: 1fr;
  }
  .availability-grid {
    grid-template-columns: 1fr;
  }
}
</style>
