<script lang="ts">
  import { browser } from '$app/environment';
  import { goto } from '$app/navigation';
  import { onMount, onDestroy } from 'svelte';
  import {
    getNodes, connectWebSocket, isAuthenticated, setBalanceMode,
    type NodeInfo, type BalancerInfo
  } from '$lib/api';
  import { Activity, Phone, Zap, AlertTriangle, Wifi, Server, Plug, Globe, ArrowLeftRight, Network, Shuffle } from 'lucide-svelte';

  let nodes: NodeInfo[] = [];
  let balancer: BalancerInfo | null = null;
  let ws: WebSocket | null = null;
  let error: string | null = null;
  let setModeBusy = false;

  if (browser && !isAuthenticated()) {
    goto('/login');
  }

  function getRole(): string | null {
    if (!browser) return null;
    const token = localStorage.getItem('token');
    if (!token) return null;
    try {
      const payload = JSON.parse(atob(token.split('.')[1]));
      return payload.role || null;
    } catch {
      return null;
    }
  }

  let role = browser ? getRole() : null;
  $: isAdmin = role === 'admin';

  onMount(() => {
    loadNodes();
    ws = connectWebSocket((msg) => {
      if (msg.type === 'nodes_update') {
        nodes = msg.payload;
      } else if (msg.type === 'balancer_update') {
        balancer = msg.payload;
      }
    });
  });

  onDestroy(() => {
    ws?.close();
  });

  async function loadNodes() {
    try {
      nodes = await getNodes();
    } catch (e: any) {
      error = e.message;
    }
  }

  async function toggleMode() {
    if (!balancer || setModeBusy) return;
    const newMode = balancer.balance_mode === 'weighted_random' ? 'best' : 'weighted_random';
    setModeBusy = true;
    try {
      await setBalanceMode(newMode);
    } catch (e: any) {
      error = e.message;
    } finally {
      setModeBusy = false;
    }
  }

  function scoreColor(score: number): string {
    if (score >= 70) return 'text-green-600';
    if (score >= 40) return 'text-yellow-600';
    if (score >= 0) return 'text-orange-600';
    return 'text-red-600';
  }

  function scoreBg(score: number): string {
    if (score >= 70) return 'bg-green-50 border-green-200';
    if (score >= 40) return 'bg-yellow-50 border-yellow-200';
    if (score >= 0) return 'bg-orange-50 border-orange-200';
    return 'bg-red-50 border-red-200';
  }

  function nodeStatus(n: NodeInfo): string {
    if (n.disabled) return 'disabled';
    if (n.is_stale) return 'stale';
    if (n.status !== 'ok') return 'degraded';
    if (n.score < 0) return 'unhealthy';
    return 'healthy';
  }

  function statusColor(s: string): string {
    switch (s) {
      case 'healthy': return 'bg-green-500';
      case 'degraded': return 'bg-yellow-500';
      default: return 'bg-red-500';
    }
  }

  function dotColor(ok: boolean, degrade?: boolean): string {
    if (ok) return 'bg-green-500';
    if (degrade) return 'bg-yellow-500';
    return 'bg-red-500';
  }

  function fmtUptime(sec: number): string {
    if (sec < 60) return `${sec}с`;
    if (sec < 3600) return `${Math.floor(sec / 60)}м`;
    if (sec < 86400) return `${Math.floor(sec / 3600)}ч`;
    return `${Math.floor(sec / 86400)}д`;
  }

  function fmtNum(n: number): string {
    if (n >= 1000) return (n / 1000).toFixed(1) + 'K';
    return String(n);
  }

  $: healthyCount = nodes.filter(n => n.score >= 0 && !n.disabled && !n.is_stale).length;
  $: totalCalls = nodes.reduce((s, n) => s + n.active_calls, 0);
  $: avgScore = nodes.length > 0 ? nodes.reduce((s, n) => s + n.score, 0) / nodes.length : 0;
  $: unhealthyList = nodes.filter(n => n.score < 0 || n.disabled || n.is_stale);
  $: fallbackPct = balancer && balancer.route_total > 0
    ? (balancer.route_fallbacks / balancer.route_total * 100).toFixed(1)
    : '0';
</script>

{#if error}
  <div class="p-4 border border-red-200 bg-red-50 text-red-700 rounded-md">
    {error}
  </div>
{/if}

<!-- Balancer Status Bar -->
{#if balancer}
  <div class="flex flex-wrap items-center gap-1 text-xs text-muted-foreground mb-4 px-3 py-2 border rounded-md bg-muted/30">
    <span class="flex items-center gap-1 mr-2">
      <span class="w-1.5 h-1.5 rounded-full {dotColor(balancer.esl_connected)}"></span>
      <Plug class="h-3 w-3" />
      ESL {balancer.esl_connected ? 'Online' : 'Offline'}
      {#if balancer.esl_uptime_sec > 0}{fmtUptime(balancer.esl_uptime_sec)}{/if}
    </span>
    <span class="opacity-30">|</span>
    <span class="flex items-center gap-1 mr-2">
      <span class="w-1.5 h-1.5 rounded-full {dotColor(balancer.nats_connected)}"></span>
      <Network class="h-3 w-3" />
      NATS {balancer.nats_connected ? 'Online' : 'Offline'}
    </span>
    <span class="opacity-30">|</span>
    <span class="flex items-center gap-1 mr-2">
      <span class="w-1.5 h-1.5 rounded-full {balancer.gateways_down > 0 ? 'bg-red-500' : 'bg-green-500'}"></span>
      <Globe class="h-3 w-3" />
      GW {balancer.gateways_up}/{balancer.gateways_total}
      {#if balancer.gateways_down > 0}
        <span class="text-red-500">({balancer.gateways_down} down)</span>
      {/if}
    </span>
    <span class="opacity-30">|</span>
    <span class="flex items-center gap-1">
      <ArrowLeftRight class="h-3 w-3" />
      R {fmtNum(balancer.route_total)}
      {#if balancer.route_fallbacks > 0}
        <span class="text-orange-500">({fallbackPct}% fb)</span>
      {/if}
    </span>
    {#if balancer.esl_connected && balancer.fs_max_sessions > 0}
      <span class="opacity-30">|</span>
      <span class="flex items-center gap-1">
        <Phone class="h-3 w-3" />
        FS {balancer.fs_active_calls}·{balancer.fs_max_sessions}
        {#if balancer.fs_uptime}
          <span class="opacity-50">{balancer.fs_uptime}</span>
        {/if}
      </span>
    {/if}
    <span class="opacity-30">|</span>
    <span class="flex items-center gap-1 ml-auto">
      <Shuffle class="h-3 w-3" />
      <span class="font-medium">{balancer.balance_mode === 'weighted_random' ? 'Weighted' : 'Best'}</span>
      {#if isAdmin}
        <button
          on:click={toggleMode}
          disabled={setModeBusy}
          class="ml-1 px-2 py-0.5 text-[10px] border rounded hover:bg-secondary transition-colors disabled:opacity-50"
          title="Переключить режим балансировки"
        >
          {setModeBusy ? '...' : 'Switch'}
        </button>
      {/if}
    </span>
  </div>
{/if}

<!-- Summary Cards -->
<div class="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4 mb-6">
  <div class="border rounded-lg p-4 bg-card">
    <div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
      <Server class="h-4 w-4" /> Всего нод
    </div>
    <div class="text-2xl font-bold">{nodes.length}</div>
  </div>

  <div class="border rounded-lg p-4 bg-card">
    <div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
      <Activity class="h-4 w-4" /> Здоровых
    </div>
    <div class="text-2xl font-bold text-green-600">{healthyCount}</div>
  </div>

  <div class="border rounded-lg p-4 bg-card">
    <div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
      <Phone class="h-4 w-4" /> Активных звонков
    </div>
    <div class="text-2xl font-bold">{totalCalls}</div>
  </div>

  <div class="border rounded-lg p-4 bg-card">
    <div class="flex items-center gap-2 text-sm text-muted-foreground mb-2">
      <Zap class="h-4 w-4" /> Средний score
    </div>
    <div class="text-2xl font-bold {scoreColor(avgScore)}">{avgScore.toFixed(1)}</div>
  </div>
</div>

<!-- Unhealthy Alerts -->
{#if unhealthyList.length > 0}
  <div class="mb-6">
    <h2 class="flex items-center gap-2 text-sm font-semibold text-destructive mb-2">
      <AlertTriangle class="h-4 w-4" /> Проблемные ноды ({unhealthyList.length})
    </h2>
    <div class="space-y-1">
      {#each unhealthyList as n}
        <div class="text-sm text-muted-foreground flex items-center gap-2">
          <span class="w-2 h-2 rounded-full {statusColor(nodeStatus(n))}"></span>
          <span class="font-mono">{n.node_id}</span>
          <span class="text-destructive">score={n.score.toFixed(0)}</span>
          {#if n.lethal_reason}
            <span class="text-red-500">— {n.lethal_reason}</span>
          {/if}
          {#if n.disabled}
            <span class="text-orange-500">— disabled: {n.disabled_reason}</span>
          {/if}
        </div>
      {/each}
    </div>
  </div>
{/if}

<!-- Node Cards -->
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
  {#each nodes as n (n.node_id)}
    <div class="border rounded-lg p-4 {scoreBg(n.score)}">
      <div class="flex items-center justify-between mb-3">
        <div class="flex items-center gap-2">
          <span class="w-2 h-2 rounded-full {statusColor(nodeStatus(n))}"></span>
          <span class="font-semibold">{n.node_id}</span>
        </div>
        <span class="text-lg font-bold {scoreColor(n.score)}">
          {n.score.toFixed(0)}
        </span>
      </div>

      <div class="grid grid-cols-2 gap-2 text-xs">
        <div>
          <span class="text-muted-foreground">Звонки:</span>
          <span class="font-mono ml-1">{n.active_calls}/{n.max_calls}</span>
        </div>
        <div>
          <span class="text-muted-foreground">CPU idle:</span>
          <span class="font-mono ml-1">{n.idle_cpu.toFixed(0)}%</span>
        </div>
        <div>
          <span class="text-muted-foreground">Load:</span>
          <span class="font-mono ml-1">{n.load_avg.toFixed(2)}</span>
        </div>
        <div>
          <span class="text-muted-foreground">Fail:</span>
          <span class="font-mono ml-1">{n.call_failure_rate.toFixed(1)}%</span>
        </div>
        <div class="col-span-2">
          <span class="text-muted-foreground">Status:</span>
          <span class="ml-1">{nodeStatus(n)}</span>
          <span class="text-muted-foreground ml-2">
            {n.seconds_ago.toFixed(0)}с назад
          </span>
          {#if n.is_stale}
            <span class="text-red-500 ml-1">STALE</span>
          {/if}
        </div>
      </div>
    </div>
  {/each}

  {#if nodes.length === 0}
    <div class="col-span-full text-center py-12 text-muted-foreground">
      <Wifi class="h-12 w-12 mx-auto mb-4 opacity-20" />
      <p>Нет зарегистрированных нод. Ожидание метрик через NATS...</p>
    </div>
  {/if}
</div>
