<script setup lang="ts">
import { computed } from 'vue'

import type { LinkSessionTelemetry, LinkTelemetry, NetworkTelemetry } from '@/types'

const props = defineProps<{
  network: NetworkTelemetry | null
}>()

const legCards = computed(() => [
  {
    key: 'a_to_d',
    label: 'A <-> D',
    data: props.network?.links?.a_to_d ?? null,
  },
  {
    key: 'd_to_b',
    label: 'D <-> B',
    data: props.network?.links?.d_to_b ?? null,
  },
])

const activeSource = computed(() => props.network?.active_control_source ?? 'none')

function formatTime(value?: string | null) {
  if (!value) {
    return 'unavailable'
  }
  return new Date(value).toLocaleString('zh-CN', { hour12: false })
}

function formatScalar(value?: number | string | null, suffix = '') {
  if (value === null || value === undefined || value === '') {
    return '--'
  }
  return `${value}${suffix}`
}

function legSessions(link: LinkTelemetry | null): Array<{ name: string; data: LinkSessionTelemetry | null }> {
  return [
    { name: 'control', data: link?.sessions?.control ?? null },
    { name: 'video', data: link?.sessions?.video ?? null },
  ]
}
</script>

<template>
  <section class="panel network-panel">
    <div class="panel-head">
      <div>
        <p class="eyebrow">Network</p>
        <h2>Dual-Leg Telemetry</h2>
      </div>
      <span class="badge" :class="{ stale: network?.telemetry_receiver?.hub_stale }">
        {{ network?.peer_status ?? 'loading' }}
      </span>
    </div>

    <div class="stats">
      <div class="stat-card">
        <span>Latency</span>
        <strong>{{ formatScalar(network?.latency_ms, ' ms') }}</strong>
      </div>
      <div class="stat-card">
        <span>Jitter</span>
        <strong>{{ formatScalar(network?.jitter_ms, ' ms') }}</strong>
      </div>
      <div class="stat-card">
        <span>Active Control</span>
        <strong>{{ activeSource }}</strong>
      </div>
      <div class="stat-card">
        <span>Lease</span>
        <strong>{{ formatScalar(network?.control_lease_remaining_ms, ' ms') }}</strong>
      </div>
      <div class="stat-card">
        <span>TX Rate</span>
        <strong>{{ formatScalar(network?.tx_kbps, ' kbps') }}</strong>
      </div>
      <div class="stat-card">
        <span>RX Rate</span>
        <strong>{{ formatScalar(network?.rx_kbps, ' kbps') }}</strong>
      </div>
    </div>

    <div class="summary telemetry-strip">
      <p><strong>Robot Fault:</strong> {{ network?.robot_health?.fault_reason ?? 'n/a' }}</p>
      <p><strong>Recovery State:</strong> {{ network?.robot_health?.recovery_state ?? 'n/a' }}</p>
      <p><strong>Health Confidence:</strong> {{ network?.robot_health?.confidence ?? 'n/a' }}</p>
      <p><strong>Health Updated:</strong> {{ formatTime(network?.robot_health?.updated_at) }}</p>
      <p><strong>Transport:</strong> {{ network?.transport ?? 'n/a' }} / {{ network?.source_mode ?? 'n/a' }}</p>
      <p><strong>Telemetry Peer:</strong> {{ network?.telemetry_receiver?.peer_id ?? 'n/a' }}</p>
      <p><strong>Telemetry Registered:</strong> {{ network?.telemetry_receiver?.registered ? 'yes' : 'no' }}</p>
      <p><strong>Hub Freshness:</strong> {{ formatTime(network?.telemetry_receiver?.hub_updated_at) }}</p>
      <p><strong>Hub State:</strong> {{ network?.telemetry_receiver?.hub_stale ? 'stale' : 'fresh' }}</p>
      <p><strong>Telemetry Reconnects:</strong> {{ network?.telemetry_receiver?.reconnect_count ?? 0 }}</p>
      <p v-if="network?.telemetry_receiver?.last_error"><strong>Hub Error:</strong> {{ network?.telemetry_receiver?.last_error }}</p>
      <p v-if="network?.telemetry_receiver?.last_server_error"><strong>Telemetry Session Error:</strong> {{ network?.telemetry_receiver?.last_server_error }}</p>
    </div>

    <div class="leg-grid">
      <article v-for="leg in legCards" :key="leg.key" class="leg-card" :class="{ stale: leg.data?.stale }">
        <div class="leg-head">
          <div>
            <p class="leg-label">{{ leg.label }}</p>
            <h3>{{ leg.data?.source ?? 'waiting' }}</h3>
          </div>
          <div class="leg-meta">
            <span class="mini-badge" :class="{ stale: leg.data?.stale }">
              {{ leg.data?.stale ? 'stale' : 'fresh' }}
            </span>
            <span class="mini-time">{{ formatTime(leg.data?.updated_at) }}</span>
          </div>
        </div>

        <div class="aggregate-grid">
          <div>
            <span>Online</span>
            <strong>{{ leg.data?.aggregate?.online_sessions ?? 0 }}</strong>
          </div>
          <div>
            <span>Max Pressure</span>
            <strong>{{ formatScalar(leg.data?.aggregate?.max_window_pressure_pct, '%') }}</strong>
          </div>
          <div>
            <span>Queued</span>
            <strong>{{ leg.data?.aggregate?.sum_snd_queue ?? 0 }}</strong>
          </div>
          <div>
            <span>In Flight Buffer</span>
            <strong>{{ leg.data?.aggregate?.sum_snd_buffer ?? 0 }}</strong>
          </div>
          <div>
            <span>Retrans Delta</span>
            <strong>{{ leg.data?.aggregate?.sum_retrans_delta ?? 0 }}</strong>
          </div>
          <div>
            <span>Repair Rate</span>
            <strong>{{ formatScalar(leg.data?.aggregate?.repair_rate_pct, '%') }}</strong>
          </div>
        </div>

        <div class="session-grid">
          <section v-for="session in legSessions(leg.data)" :key="session.name" class="session-card">
            <div class="session-head">
              <div>
                <p class="session-label">{{ session.name }}</p>
                <h4>{{ session.data?.peer_id ?? 'unassigned' }}</h4>
              </div>
              <span class="mini-badge" :class="{ stale: session.data?.stale, active: session.data?.connected }">
                {{ session.data?.connected ? 'online' : 'idle' }}
              </span>
            </div>

            <div class="kv-grid">
              <p><strong>Updated:</strong> {{ formatTime(session.data?.updated_at) }}</p>
              <p><strong>SRTT:</strong> {{ formatScalar(session.data?.kcp?.srtt_ms, ' ms') }}</p>
              <p><strong>RTTVAR:</strong> {{ formatScalar(session.data?.kcp?.srttvar_ms, ' ms') }}</p>
              <p><strong>RTO:</strong> {{ formatScalar(session.data?.kcp?.rto_ms, ' ms') }}</p>
              <p><strong>SND WND:</strong> {{ formatScalar(session.data?.kcp?.snd_wnd) }}</p>
              <p><strong>RMT WND:</strong> {{ formatScalar(session.data?.kcp?.rmt_wnd) }}</p>
              <p><strong>Inflight:</strong> {{ formatScalar(session.data?.kcp?.inflight) }}</p>
              <p><strong>Window Limit:</strong> {{ formatScalar(session.data?.kcp?.window_limit) }}</p>
              <p><strong>Pressure:</strong> {{ formatScalar(session.data?.kcp?.window_pressure_pct, '%') }}</p>
              <p><strong>SND Queue:</strong> {{ formatScalar(session.data?.kcp?.snd_queue) }} / {{ session.data?.trend?.snd_queue_trend ?? 'stable' }}</p>
              <p><strong>SND Buffer:</strong> {{ formatScalar(session.data?.kcp?.snd_buffer) }} / {{ session.data?.trend?.snd_buffer_trend ?? 'stable' }}</p>
              <p><strong>Queue Delta:</strong> {{ formatScalar(session.data?.trend?.snd_queue_delta) }}</p>
              <p><strong>Buffer Delta:</strong> {{ formatScalar(session.data?.trend?.snd_buffer_delta) }}</p>
              <p><strong>Retrans:</strong> {{ formatScalar(session.data?.trend?.retrans_delta) }}</p>
              <p><strong>Fast Retrans:</strong> {{ formatScalar(session.data?.trend?.fast_retrans_delta) }}</p>
              <p><strong>Lost:</strong> {{ formatScalar(session.data?.trend?.lost_delta) }}</p>
              <p><strong>Repeat:</strong> {{ formatScalar(session.data?.trend?.repeat_delta) }}</p>
              <p><strong>Repair Rate:</strong> {{ formatScalar(session.data?.trend?.repair_rate_pct, '%') }}</p>
              <p v-if="session.data?.app"><strong>App Bytes:</strong> tx={{ session.data.app.send_bytes ?? 0 }} / rx={{ session.data.app.recv_bytes ?? 0 }}</p>
              <p v-if="session.data?.app"><strong>Registered:</strong> {{ session.data.app.registered ? 'yes' : 'no' }}</p>
              <p v-if="session.data?.app?.last_server_error"><strong>Server Error:</strong> {{ session.data.app.last_server_error }}</p>
            </div>
          </section>
        </div>
      </article>
    </div>

    <div class="summary">
      <p><strong>Combined:</strong> sessions={{ network?.combined?.connected_sessions ?? 0 }} send={{ network?.combined?.send_bytes ?? 0 }}B recv={{ network?.combined?.recv_bytes ?? 0 }}B</p>
      <p><strong>Native UDP:</strong> {{ network?.ingress?.native_udp?.bind_addr ?? 'n/a' }} packets={{ network?.ingress?.native_udp?.packets_received ?? 0 }} invalid={{ network?.ingress?.native_udp?.invalid_packets ?? 0 }}</p>
      <p><strong>Control Sender:</strong> {{ network?.control?.sender?.peer_id ?? 'n/a' }} -> {{ network?.control?.sender?.target_peer ?? 'n/a' }} sends={{ network?.control?.sender?.send_count ?? 0 }} registered={{ network?.control?.sender?.registered ? 'yes' : 'no' }}</p>
      <p><strong>Control Reconnects:</strong> {{ network?.control?.sender?.reconnect_count ?? 0 }}</p>
      <p v-if="network?.control?.sender?.last_server_error"><strong>Control Session Error:</strong> {{ network?.control?.sender?.last_server_error }}</p>
    </div>
  </section>
</template>

<style scoped>
.network-panel {
  display: grid;
  gap: 18px;
}

.panel-head,
.leg-head,
.session-head {
  display: flex;
  justify-content: space-between;
  gap: 12px;
  align-items: start;
}

.eyebrow,
.leg-label,
.session-label {
  margin: 0 0 4px;
  color: #5bd3b5;
  text-transform: uppercase;
  letter-spacing: 0.14em;
  font-size: 12px;
  font-weight: 700;
}

h2,
h3,
h4 {
  margin: 0;
}

h2 {
  font-size: 24px;
}

h3 {
  font-size: 22px;
}

h4 {
  font-size: 16px;
}

.badge,
.mini-badge {
  border-radius: 999px;
  text-transform: uppercase;
  font-weight: 700;
}

.badge {
  padding: 8px 12px;
  background: rgba(40, 199, 111, 0.16);
  color: #63e6a9;
  font-size: 12px;
}

.mini-badge {
  padding: 6px 10px;
  background: rgba(91, 211, 181, 0.12);
  color: #8ff2db;
  font-size: 11px;
}

.badge.stale,
.mini-badge.stale {
  background: rgba(255, 165, 0, 0.16);
  color: #ffd08a;
}

.mini-badge.active {
  background: rgba(64, 187, 255, 0.16);
  color: #98dcff;
}

.stats,
.leg-grid,
.session-grid,
.aggregate-grid,
.kv-grid {
  display: grid;
  gap: 12px;
}

.stats {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.leg-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.session-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.aggregate-grid {
  grid-template-columns: repeat(3, minmax(0, 1fr));
}

.kv-grid {
  grid-template-columns: repeat(2, minmax(0, 1fr));
}

.stat-card,
.summary,
.leg-card,
.session-card {
  padding: 14px;
  border-radius: 18px;
  background: rgba(7, 14, 26, 0.8);
  border: 1px solid rgba(133, 147, 169, 0.2);
  color: #d5dbee;
}

.stat-card span,
.aggregate-grid span {
  display: block;
  margin-bottom: 8px;
  color: #8d99b3;
  font-size: 12px;
}

.stat-card strong,
.aggregate-grid strong {
  font-size: 22px;
}

.summary p,
.kv-grid p {
  margin: 0;
}

.summary p + p {
  margin-top: 8px;
}

.telemetry-strip {
  display: grid;
  grid-template-columns: repeat(4, minmax(0, 1fr));
  gap: 10px;
}

.leg-card {
  display: grid;
  gap: 16px;
}

.leg-card.stale {
  border-color: rgba(255, 165, 0, 0.3);
}

.leg-meta {
  display: grid;
  justify-items: end;
  gap: 8px;
}

.mini-time {
  color: #9aa6c2;
  font-size: 12px;
}

.session-card {
  display: grid;
  gap: 12px;
  background: rgba(11, 19, 35, 0.86);
}

@media (max-width: 1200px) {
  .stats,
  .aggregate-grid,
  .telemetry-strip {
    grid-template-columns: repeat(2, minmax(0, 1fr));
  }

  .leg-grid,
  .session-grid,
  .kv-grid {
    grid-template-columns: 1fr;
  }
}

@media (max-width: 720px) {
  .stats,
  .aggregate-grid,
  .telemetry-strip,
  .kv-grid {
    grid-template-columns: 1fr;
  }
}
</style>
