import { useWebSocket } from '../hooks/useWebSocket';
import { api } from '../api/client';
import { useState, useEffect, useMemo, type CSSProperties } from 'react';
import { Link } from 'react-router-dom';
import type { Share } from '../types';
import HashrateChart from '../components/Charts/HashrateChart';
import GaugeRing from '../components/Charts/GaugeRing';
import NeonCard from '../components/NeonCard/NeonCard';
import { FleetPipelineStatus, ActivityPulse } from '../components/Visual/VisualComponents';
import {
  AlertBanner,
  PoolStatusPanel,
  AIActivityPanel,
  EarningsEstimator,
  FleetHealthCard,
  ContributionBars,
  UnderperformerList,
  OSArchBreakdown,
  LANGroupView,
} from '../components/Fleet/FleetPanels';
import AgentRemoteActions from '../components/Fleet/AgentRemoteActions';
import FleetToolbar from '../components/Fleet/FleetToolbar';
import ErrorBoundary from '../components/ErrorBoundary';
import FleetTopologyMap from '../components/Visual/3D/FleetTopologyMap';
import MatrixStreamOverlay from '../components/Visual/MatrixStreamOverlay';
import {
  DEFAULT_FLEET_FILTERS,
  filterFleetAgents,
  agentIsIdleMiner,
  formatHashrate,
  formatUptime,
} from '../help/fleetFilters';
import type { FleetFilterState } from '../help/fleetFilters';
import {
  computeFleetHealth,
  contributionBars,
  findUnderperformers,
  fleetMedianHashrate,
  groupBySubnet,
  osArchBreakdown,
} from '../help/fleetAnalytics';
import './Pages.css';
export default function DashboardPage() {
  const { isConnected, agents, recentShares, fleetAlerts, poolStatus, aiActivity } = useWebSocket();
  const [shares, setShares] = useState<Share[]>([]);
  const [restAlerts, setRestAlerts] = useState<typeof fleetAlerts>([]);
  const [restPools, setRestPools] = useState<typeof poolStatus>([]);
  const [restAI, setRestAI] = useState<typeof aiActivity>([]);
  const [subtitle, setSubtitle] = useState('security is just an emotion');
  const [hashHistory, setHashHistory] = useState<{ time: string; value: number }[]>([]);
  const [cpuHistory, setCpuHistory] = useState<{ time: string; value: number }[]>([]);
  const [memHistory, setMemHistory] = useState<{ time: string; value: number }[]>([]);
  const [hasBuilds, setHasBuilds] = useState(false);
  const [filters, setFilters] = useState<FleetFilterState>(DEFAULT_FLEET_FILTERS);
  const [selectedIds, setSelectedIds] = useState<Set<string>>(new Set());
  const [bulkBusy, setBulkBusy] = useState(false);
  const [showMatrix, setShowMatrix] = useState(false);
  const [advancedMode, setAdvancedMode] = useState<boolean>(() => {
    try { return localStorage.getItem('aether-dash-advanced') === '1'; } catch { return false; }
  });
  const [xmrPrice, setXmrPrice] = useState<number | null>(null);

  const toggleAdvanced = () =>
    setAdvancedMode((prev) => {
      const next = !prev;
      try { localStorage.setItem('aether-dash-advanced', next ? '1' : '0'); } catch { /* ignore */ }
      return next;
    });

  useEffect(() => {
    api.getRecentShares(20).then(setShares).catch(console.error);
    api.listBuilds().then((b) => setHasBuilds(b.length > 0)).catch(console.error);
    api.getConfig()
      .then((cfg) => {
        const s = cfg.server?.dashboard_subtitle?.trim();
        if (s) setSubtitle(s);
      })
      .catch(console.error);
    api.getAlerts().then(setRestAlerts).catch(console.error);
    api.getPoolStatus().then(setRestPools).catch(console.error);
    api.getAIActivity().then(setRestAI).catch(console.error);
    // XMR market price — refresh every 10 min matching server-side cache TTL
    const fetchPrice = () => api.getXmrPrice().then((r) => setXmrPrice(r.usd)).catch(() => {});
    fetchPrice();
    const priceTimer = setInterval(fetchPrice, 10 * 60 * 1000);
    return () => clearInterval(priceTimer);
  }, []);

  useEffect(() => {
    if (recentShares.length > 0) {
      setShares((prev) => {
        const merged = [...recentShares, ...prev];
        const seen = new Set<string>();
        return merged.filter((s) => {
          const key = s.id != null ? String(s.id) : `${s.agent_id}-${s.hash}-${s.timestamp}`;
          if (seen.has(key)) return false;
          seen.add(key);
          return true;
        }).slice(0, 20);
      });
    }
  }, [recentShares]);

  const totalHashrate = agents.reduce((sum, a) => sum + a.hashrate_15m, 0);
  const onlineCount = agents.filter((a) => a.status === 'online').length;
  const totalShares = agents.reduce((sum, a) => sum + a.shares_total, 0);
  const acceptedShares = agents.reduce((sum, a) => sum + a.shares_good, 0);
  const rejectedShares = agents.reduce((sum, a) => sum + a.shares_bad, 0);
  const acceptRate = totalShares > 0 ? (acceptedShares / totalShares) * 100 : 0;
  const avgCpu = agents.length > 0 ? agents.reduce((s, a) => s + a.cpu_usage_pct, 0) / agents.length : 0;
  const avgMem = agents.length > 0 ? agents.reduce((s, a) => s + a.memory_usage_pct, 0) / agents.length : 0;
  const onlinePct = agents.length > 0 ? (onlineCount / agents.length) * 100 : 0;

  useEffect(() => {
    const now = new Date().toLocaleTimeString();
    setHashHistory((prev) => [...prev.slice(-59), { time: now, value: totalHashrate }]);
    setCpuHistory((prev) => [...prev.slice(-59), { time: now, value: avgCpu }]);
    setMemHistory((prev) => [...prev.slice(-59), { time: now, value: avgMem }]);
  }, [totalHashrate, avgCpu, avgMem]);

  const filteredAgents = useMemo(() => filterFleetAgents(agents, filters), [agents, filters]);

  const topAgents = useMemo(
    () => [...filteredAgents].sort((a, b) => b.hashrate_15m - a.hashrate_15m).slice(0, 12),
    [filteredAgents]
  );
  const maxAgentHash = Math.max(...topAgents.map((a) => a.hashrate_15m), 1);

  const activityItems = useMemo(
    () =>
      shares.slice(0, 12).map((s) => ({
        id: String(s.id ?? `${s.agent_id}-${s.hash}`),
        label: s.accepted ? 'OK' : 'BAD',
        ok: s.accepted,
        time: s.timestamp ? new Date(s.timestamp).toLocaleTimeString() : undefined,
      })),
    [shares]
  );

  const totalShareCount = agents.reduce((sum, a) => sum + a.shares_total, 0);
  const alerts = fleetAlerts.length > 0 ? fleetAlerts : restAlerts;
  const pools = poolStatus.length > 0 ? poolStatus : restPools;
  const aiEntries = aiActivity.length > 0 ? aiActivity : restAI;
  const agentNameMap = useMemo(
    () => Object.fromEntries(agents.map((a) => [a.id, a.name])),
    [agents]
  );

  // ── Analytics ─────────────────────────────────────────────────────────────
  const fleetHealth = useMemo(() => computeFleetHealth(agents, pools), [agents, pools]);
  const contribs = useMemo(() => contributionBars(agents), [agents]);
  const underperformers = useMemo(() => findUnderperformers(agents), [agents]);
  const medianHash = useMemo(() => fleetMedianHashrate(agents), [agents]);
  const lanGroups = useMemo(() => groupBySubnet(agents), [agents]);
  const platforms = useMemo(() => osArchBreakdown(agents), [agents]);

  const handleBulkAction = async (action: string) => {
    let targetIds = [...selectedIds];
    if (action === 'restart_idle') {
      targetIds = agents.filter((a) => selectedIds.has(a.id) && agentIsIdleMiner(a)).map((a) => a.id);
      if (targetIds.length === 0) {
        alert('No selected online agents with idle hashrate.');
        return;
      }
      action = 'restart';
    }
    const onlineIds = targetIds.filter((id) => agents.find((a) => a.id === id)?.status === 'online');
    if (onlineIds.length === 0) return;
    if (action === 'stop' && !window.confirm(`Stop ${onlineIds.length} agent(s)?`)) return;
    setBulkBusy(true);
    try {
      await api.sendBulkCommand(onlineIds, action);
    } catch (err) {
      console.error(err);
      alert(err instanceof Error ? err.message : 'Bulk command failed');
    } finally {
      setBulkBusy(false);
    }
  };

  return (
    <div className="page fade-in command-deck">
      <AlertBanner alerts={alerts} />

      {/* Fleet Health — always above the fold */}
      <FleetHealthCard health={fleetHealth} />

      <header className="deck-hero">
        <div className="deck-hero-text">
          <p className="deck-eyebrow font-tech">PERSONAL NETWORK · LIVE TELEMETRY</p>
          <h1>Command Deck</h1>
          <p className="page-subtitle">{subtitle}</p>
        </div>
        <div className="deck-hero-status">
          <div className={`live-beacon ${isConnected ? 'on' : ''}`}>
            <span className="beacon-ring" />
            <span className="beacon-core" />
          </div>
          <div>
            <span className="font-tech live-label">{isConnected ? 'SIGNAL LOCKED' : 'RECONNECTING'}</span>
            <span className="live-sub">{agents.length} nodes registered</span>
          </div>
          <button
            className={`dash-mode-btn${advancedMode ? ' active' : ''}`}
            onClick={toggleAdvanced}
            title={advancedMode ? 'Switch to Overview (hide charts / logs)' : 'Switch to Advanced (show all panels)'}
          >
            {advancedMode ? '[OVERVIEW]' : '[ADVANCED]'}
          </button>
          {advancedMode && (
            <button
              className="button matrix-toggle-btn"
              onClick={() => setShowMatrix(true)}
              style={{ background: 'transparent', border: '1px solid #0f0', color: '#0f0', fontFamily: 'monospace' }}
            >
              [RAW_STREAM]
            </button>
          )}
        </div>
      </header>

      <NeonCard accent="green" className="section" hud>
        <h2 className="section-title font-display" style={{ marginBottom: '0.25rem' }}>
          <span className="section-ornament">◆</span> Fleet Pipeline
          <span className="section-line" />
        </h2>
        <p className="form-hint" style={{ marginTop: 0 }}>
          Visual progress — lit nodes mean that stage is active. <Link to="/guide">Open Field Guide →</Link>
        </p>
        <FleetPipelineStatus
          hasBuilds={hasBuilds}
          agentCount={agents.length}
          onlineCount={onlineCount}
          hasHashrate={totalHashrate > 0}
          hasShares={totalShareCount > 0}
        />
      </NeonCard>

      <section className="gauge-row">
        <NeonCard accent="cyan" className="gauge-card" hud>
          <GaugeRing
            value={totalHashrate}
            max={Math.max(totalHashrate * 1.2, 1000)}
            label="Fleet Hash"
            sublabel="15m avg"
            color="var(--neon-cyan)"
            size={110}
          />
        </NeonCard>
        <NeonCard accent="green" className="gauge-card" hud>
          <GaugeRing value={onlinePct} label="Online" sublabel={`${onlineCount}/${agents.length}`} color="var(--neon-green)" size={110} />
        </NeonCard>
        <NeonCard accent="purple" className="gauge-card" hud>
          <GaugeRing value={acceptRate} label="Accept" sublabel="share rate" color="var(--neon-purple)" size={110} />
        </NeonCard>
        <NeonCard accent="amber" className="gauge-card" hud>
          <GaugeRing value={avgCpu} label="CPU" sublabel={`RAM ${avgMem.toFixed(0)}%`} color="var(--neon-amber)" size={110} />
        </NeonCard>
      </section>

      <div className="grid-4 stats-grid steampunk-stats">
        <NeonCard accent="cyan" className="stat-card-wrap">
          <div className="stat-label font-tech">Total Hashrate</div>
          <div className="stat-value hashrate neon-glow-cyan">{formatHashrate(totalHashrate)}</div>
          <div className="stat-sub">{onlineCount} engines firing</div>
        </NeonCard>
        <EarningsEstimator hashrate={totalHashrate} xmrPrice={xmrPrice} />
        <NeonCard accent="green" className="stat-card-wrap">
          <div className="stat-label font-tech">Fleet Online</div>
          <div className="stat-value accepted">{onlineCount} <span className="stat-dim">/ {agents.length}</span></div>
          <div className="stat-sub">{agents.length - onlineCount} dormant</div>
        </NeonCard>
        <NeonCard accent="purple" className="stat-card-wrap">
          <div className="stat-label font-tech">Accept Rate</div>
          <div className="stat-value neon-glow-purple">{acceptRate.toFixed(1)}%</div>
          <div className="stat-sub">{acceptedShares} valid · {rejectedShares} rejected</div>
        </NeonCard>
        <NeonCard accent="amber" className="stat-card-wrap">
          <div className="stat-label font-tech">Resources</div>
          <div className="stat-value">{avgCpu.toFixed(0)}% CPU</div>
          <div className="stat-sub">{avgMem.toFixed(0)}% memory · fleet mean</div>
        </NeonCard>
      </div>

      {/* ── Analytics row — always visible ─────────────────────────────────── */}
      <ContributionBars bars={contribs} xmrPrice={xmrPrice} />
      <UnderperformerList underperformers={underperformers} medianHashrate={medianHash} />
      {(platforms.length > 0 || lanGroups.length > 1) && (
        <div className="grid-2" style={{ gap: '1rem', marginTop: '1rem' }}>
          <OSArchBreakdown platforms={platforms} />
          <LANGroupView groups={lanGroups} />
        </div>
      )}

      <PoolStatusPanel pools={pools} />

      {/* ── Advanced-only panels ─────────────────────────────────────────────── */}
      {advancedMode && <AIActivityPanel entries={aiEntries} agentNames={agentNameMap} />}

      <div className="grid-2 chart-row">
        <NeonCard accent="cyan" tilt3d>
          <HashrateChart data={hashHistory} title="Fleet Hashrate Wave" color="#00f5ff" unit="H/s" height={300} />
        </NeonCard>
        {advancedMode && (
          <NeonCard accent="magenta" tilt3d>
            <HashrateChart data={cpuHistory} title="CPU Pressure" color="#ff2da6" unit="%" height={300} />
          </NeonCard>
        )}
      </div>

      {advancedMode && (
        <NeonCard accent="brass" className="chart-row-full" tilt3d>
          <HashrateChart data={memHistory} title="Memory Load — Fleet Average" color="#ffb020" unit="%" height={220} />
        </NeonCard>
      )}

      <NeonCard accent="purple" className="section" hud>
        <h2 className="section-title font-display">
          <span className="section-ornament">◆</span> Share Activity Pulse
          <span className="section-line" />
        </h2>
        <ActivityPulse items={activityItems} />
      </NeonCard>

      <section className="section">
        <ErrorBoundary
          fallback={
            <div className="card">
              <p className="form-hint">3D fleet map unavailable on this GPU — rest of the deck still works.</p>
            </div>
          }
        >
          <FleetTopologyMap agents={agents} />
        </ErrorBoundary>
      </section>

      <section className="section">
        <h2 className="section-title font-display">
          <span className="section-ornament">◆</span> Machine Roster
          <span className="section-line" />
        </h2>
        {agents.length > 0 && (
          <FleetToolbar
            agents={agents}
            filters={filters}
            onChange={setFilters}
            selectedCount={selectedIds.size}
            filteredCount={filteredAgents.length}
            onSelectAllFiltered={() => setSelectedIds(new Set(filteredAgents.map((a) => a.id)))}
            onBulkAction={handleBulkAction}
            bulkBusy={bulkBusy}
          />
        )}
        <div className="agent-grid">          {agents.length === 0 && (
            <NeonCard accent="brass" className="empty-state">
              <div className="empty-icon">⚙</div>
              <h3>No miners on the wire</h3>
              <p>Forge an installer, deploy once per machine — nodes appear here with live neon telemetry.</p>
            </NeonCard>
          )}
          {topAgents.map((agent, i) => (
            <NeonCard
              key={agent.id}
              accent={agent.status === 'online' ? 'cyan' : 'brass'}
              className="agent-card detailed machine-panel"
              style={{ animationDelay: `${i * 0.05}s` } as CSSProperties}
            >
              <div className="agent-card-header">
                <div className="agent-name">
                  <input
                    type="checkbox"
                    className="checkbox"
                    checked={selectedIds.has(agent.id)}
                    onChange={(e) => {
                      setSelectedIds((prev) => {
                        const next = new Set(prev);
                        if (e.target.checked) next.add(agent.id);
                        else next.delete(agent.id);
                        return next;
                      });
                    }}
                  />
                  <span className={`status-dot ${agent.status}`} />
                  <span>{agent.name}</span>
                  {agent.platform && (
                    <span className="agent-tag-chip platform-badge" title={agent.os_version || agent.platform}>
                      {agent.platform}{agent.arch ? `/${agent.arch}` : ''}
                    </span>
                  )}
                </div>
                <span className={`status-badge ${agent.status}`}>{agent.status}</span>
              </div>
              {(agent.tags?.length ?? 0) > 0 && (
                <div style={{ marginBottom: '0.35rem' }}>
                  {agent.tags!.map((t) => (
                    <span key={t} className="agent-tag-chip">{t}</span>
                  ))}
                </div>
              )}              <div className="agent-hash-bar">
                <div
                  className="agent-hash-fill"
                  style={{ width: `${(agent.hashrate_15m / maxAgentHash) * 100}%` }}
                />
              </div>
              <div className="agent-detail-lines">
                <div><span>Hash 15m</span><strong className="neon-glow-cyan">{formatHashrate(agent.hashrate_15m)}</strong></div>
                <div><span>Hash 1m</span><strong>{formatHashrate(agent.hashrate_1m)}</strong></div>
                <div><span>CPU / RAM</span><strong>{agent.cpu_usage_pct.toFixed(0)}% / {agent.memory_usage_pct.toFixed(0)}%</strong></div>
                <div><span>Hardware</span><strong>{agent.cpu_cores} cores · {agent.memory_gb} GB</strong></div>
                <div><span>Shares</span><strong>{agent.shares_good} ok · {agent.shares_bad} bad</strong></div>
                <div><span>Node</span><strong className="mono-sm">{agent.ip || '—'} · {agent.id.slice(0, 8)}</strong></div>
                <div><span>Uptime</span><strong>{formatUptime(agent.uptime_seconds)}</strong></div>
              </div>
              <AgentRemoteActions agent={agent} compact online={agent.status === 'online'} />
            </NeonCard>
          ))}
          {agents.length > 0 && topAgents.length === 0 && (
            <NeonCard accent="brass" className="empty-state">
              <p>No agents match current filters.</p>
            </NeonCard>
          )}
        </div>
      </section>
      {advancedMode && (
        <section className="section">
          <h2 className="section-title font-display">
            <span className="section-ornament">◆</span> Share Log
            <span className="section-line" />
          </h2>
          <NeonCard accent="brass" className="table-card" hud>
            <table className="shares-table steampunk-table">
              <thead>
                <tr>
                  <th>Time</th>
                  <th>Agent</th>
                  <th>Status</th>
                  <th>Hash</th>
                </tr>
              </thead>
              <tbody>
                {shares.length === 0 && (
                  <tr><td colSpan={4} className="empty-table">No shares yet — awaiting proof of work...</td></tr>
                )}
                {shares.map((share) => (
                  <tr key={share.id}>
                    <td className="time-cell font-tech">{formatTime(share.timestamp)}</td>
                    <td className="mono-sm">{share.agent_id?.substring(0, 8)}…</td>
                    <td>
                      <span className={`status-badge ${share.accepted ? 'online' : 'error'}`}>
                        {share.accepted ? 'Accepted' : 'Rejected'}
                      </span>
                    </td>
                    <td className="hash-cell mono-sm">{share.hash?.substring(0, 24)}…</td>
                  </tr>
                ))}
              </tbody>
            </table>
          </NeonCard>
        </section>
      )}
      <MatrixStreamOverlay active={showMatrix} onClose={() => setShowMatrix(false)} />
      <footer style={{ marginTop: '3rem', paddingTop: '1rem', borderTop: '1px solid #333', textAlign: 'center', color: '#ff4444', fontSize: '0.85rem', fontFamily: 'monospace' }}>
        ⚠️ DISCLAIMER: Use only on personal machines on your own network. Anything else is a crime.
      </footer>
    </div>
  );
}

function formatTime(t: string): string {
  return new Date(t).toLocaleTimeString();
}
