import { useState, useMemo, useCallback } from 'react';
import {
  Activity,
  AlertTriangle,
  HeartPulse,
  Timer,
  Percent,
  RefreshCw,
} from 'lucide-react';
import { useQueryClient } from '@tanstack/react-query';
import { Card } from '@/components/ui/Card';
import { Panel } from '@/components/ui/Panel';
import { Spinner } from '@/components/ui/Spinner';
import { EmptyState } from '@/components/ui/EmptyState';
import { SearchInput } from '@/components/ui/SearchInput';
import SigmaGraph, { type SigmaGraphNode, type SigmaGraphEdge } from '@/components/graph/SigmaGraph';
import { HEALTH_COLORS } from '@/components/graph/graphConfig';
import { useOtelStats } from '@/hooks/useOtelStats';
import { useOtelHealth } from '@/hooks/useOtelHealth';

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

const asRecord = (v: unknown) =>
  v && typeof v === 'object' ? (v as Record<string, unknown>) : {};
const num = (v: unknown) => (typeof v === 'number' ? v : 0);
const str = (v: unknown) => (typeof v === 'string' ? v : '');
const arr = (v: unknown) => (Array.isArray(v) ? v : []);

type Gradient = 'blue' | 'green' | 'amber' | 'red' | 'none';

function errorRateGradient(rate: number): Gradient {
  if (rate > 5) return 'red';
  if (rate > 1) return 'amber';
  return 'green';
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

export default function OtelPage() {
  const queryClient = useQueryClient();

  // --- Filter state ---
  const [serviceFilter, setServiceFilter] = useState('');
  const [statusFilter, setStatusFilter] = useState('all');
  const [graphSearch, setGraphSearch] = useState('');
  const [hoveredNode, setHoveredNode] = useState<string | null>(null);
  const [hoverPos, setHoverPos] = useState<{ x: number; y: number } | null>(null);

  // --- Data hooks ---
  const otelStats = useOtelStats();
  const otelHealth = useOtelHealth();

  // --- Derived data ---
  const stats = asRecord(otelStats.data);
  const health = asRecord(otelHealth.data);
  const services = arr(health.services);

  // Health counts
  const healthCounts = useMemo(() => {
    const counts = { healthy: 0, degraded: 0, unhealthy: 0 };
    services.forEach((s: unknown) => {
      const rec = asRecord(s);
      const st = str(rec.status).toLowerCase();
      if (st === 'healthy' || st === 'ok') counts.healthy++;
      else if (st === 'degraded' || st === 'warn') counts.degraded++;
      else if (st === 'unhealthy' || st === 'error') counts.unhealthy++;
      else counts.healthy++;
    });
    return counts;
  }, [services]);

  const avgLatency = num(health.avg_latency_ms ?? stats.avg_latency_ms);
  const totalSpans = num(stats.spans);
  const errorSpans = num(stats.error_spans);
  const errorRate = totalSpans > 0 ? (errorSpans / totalSpans) * 100 : 0;

  // Service names for dropdown
  const serviceNames = useMemo(
    () => services.map((s: unknown) => str(asRecord(s).name)).filter(Boolean),
    [services],
  );

  // Service map graph data
  const { nodes, edges } = useMemo(() => {
    const n: SigmaGraphNode[] = [];
    const e: SigmaGraphEdge[] = [];

    let filteredServices = services;
    if (serviceFilter) {
      filteredServices = services.filter((s: unknown) => str(asRecord(s).name) === serviceFilter);
    }
    if (statusFilter !== 'all') {
      filteredServices = filteredServices.filter((s: unknown) => {
        const st = str(asRecord(s).status).toLowerCase();
        if (statusFilter === 'healthy') return st === 'healthy' || st === 'ok';
        if (statusFilter === 'degraded') return st === 'degraded' || st === 'warn';
        if (statusFilter === 'unhealthy') return st === 'unhealthy' || st === 'error';
        return true;
      });
    }

    filteredServices.forEach((s: unknown) => {
      const rec = asRecord(s);
      const name = str(rec.name) || str(rec.service_name);
      const st = str(rec.status).toLowerCase();
      const color =
        HEALTH_COLORS[st] ??
        (st === 'ok' ? HEALTH_COLORS.healthy : HEALTH_COLORS.healthy);
      const vol = num(rec.request_count ?? rec.volume);
      n.push({
        id: name,
        label: name,
        color,
        size: vol > 0 ? Math.max(4, Math.min(Math.log10(vol + 1) * 4, 16)) : 6,
      });

      const deps = arr(rec.dependencies ?? rec.connections ?? rec.edges);
      deps.forEach((d: unknown) => {
        const target = typeof d === 'string' ? d : str(asRecord(d).target ?? asRecord(d).name);
        if (target) {
          e.push({ source: name, target });
        }
      });
    });

    return { nodes: n, edges: e };
  }, [services, serviceFilter, statusFilter]);

  const isLoading = otelStats.isLoading || otelHealth.isLoading;
  const isRefreshing = otelStats.isFetching || otelHealth.isFetching;

  const handleRefresh = () => {
    queryClient.invalidateQueries({ queryKey: ['otel'] });
  };

  // Node hover handler
  const handleNodeHover = useCallback(
    (nodeId: string | null) => {
      setHoveredNode(nodeId);
      if (!nodeId) setHoverPos(null);
    },
    [],
  );

  const handleGraphMouseMove = useCallback(
    (e: React.MouseEvent) => {
      if (hoveredNode) {
        setHoverPos({ x: e.clientX, y: e.clientY });
      }
    },
    [hoveredNode],
  );

  // Hovered service info
  const hoveredService = useMemo(() => {
    if (!hoveredNode) return null;
    const s = services.find(
      (sv: unknown) =>
        str(asRecord(sv).name) === hoveredNode ||
        str(asRecord(sv).service_name) === hoveredNode,
    );
    return s ? asRecord(s) : null;
  }, [hoveredNode, services]);

  return (
    <div className="space-y-6">
      {/* Filter Bar + Refresh */}
      <div className="flex flex-wrap items-center gap-3">
        <select
          className="bg-surface border border-border rounded-md px-3 py-2 text-sm text-text-primary focus:outline-none focus:border-accent-blue"
          value={serviceFilter}
          onChange={(e) => setServiceFilter(e.target.value)}
        >
          <option value="">All Services</option>
          {serviceNames.map((s: string) => (
            <option key={s} value={s}>{s}</option>
          ))}
        </select>

        <select
          className="bg-surface border border-border rounded-md px-3 py-2 text-sm text-text-primary focus:outline-none focus:border-accent-blue"
          value={statusFilter}
          onChange={(e) => setStatusFilter(e.target.value)}
        >
          <option value="all">All Statuses</option>
          <option value="healthy">Healthy</option>
          <option value="degraded">Degraded</option>
          <option value="unhealthy">Unhealthy</option>
        </select>

        <div className="flex-1" />

        <button
          onClick={handleRefresh}
          disabled={isRefreshing}
          className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-md border border-border bg-surface text-text-secondary hover:text-text-primary hover:border-accent-amber transition-colors disabled:opacity-50"
        >
          <RefreshCw className={`w-3.5 h-3.5 ${isRefreshing ? 'animate-spin' : ''}`} />
          Refresh
        </button>
      </div>

      {/* Stats Row */}
      {isLoading ? (
        <div className="flex items-center justify-center py-8">
          <Spinner size="lg" />
        </div>
      ) : (
        <section className="grid grid-cols-2 sm:grid-cols-3 lg:grid-cols-5 gap-4">
          <Card title="Healthy" value={healthCounts.healthy} icon={HeartPulse} gradient="green" subtitle="services" />
          <Card title="Degraded" value={healthCounts.degraded} icon={AlertTriangle} gradient="amber" subtitle="services" />
          <Card title="Unhealthy" value={healthCounts.unhealthy} icon={AlertTriangle} gradient="red" subtitle="services" />
          <Card title="Avg Latency" value={avgLatency > 0 ? `${avgLatency.toFixed(1)}ms` : '--'} icon={Timer} gradient="blue" subtitle="milliseconds" />
          <Card title="Error Rate" value={`${errorRate.toFixed(1)}%`} icon={Percent} gradient={errorRateGradient(errorRate)} subtitle={`${errorSpans} error spans`} />
        </section>
      )}

      {/* Service Map */}
      <Panel
        title="Service Map"
        actions={
          <SearchInput
            value={graphSearch}
            onChange={setGraphSearch}
            placeholder="Search services..."
          />
        }
      >
        <div className="relative" onMouseMove={handleGraphMouseMove}>
          {nodes.length === 0 ? (
            <EmptyState
              icon={Activity}
              title="No services found"
              description="Service data will appear once OTel telemetry is ingested."
            />
          ) : (
            <SigmaGraph
              nodes={nodes}
              edges={edges}
              height="500px"
              searchQuery={graphSearch}
              onNodeHover={handleNodeHover}
            />
          )}

          {hoveredNode && hoverPos && (
            <div
              className="fixed z-50 pointer-events-none bg-surface-elevated border border-border rounded-md px-3 py-2 shadow-lg text-xs"
              style={{ left: hoverPos.x + 12, top: hoverPos.y - 10 }}
            >
              <p className="font-medium text-text-primary">{hoveredNode}</p>
              {hoveredService && (
                <p className="text-text-secondary mt-0.5">
                  Status:{' '}
                  <span
                    style={{
                      color: HEALTH_COLORS[str(hoveredService.status).toLowerCase()] ?? '#94a3b8',
                    }}
                  >
                    {str(hoveredService.status)}
                  </span>
                </p>
              )}
            </div>
          )}
        </div>
      </Panel>
    </div>
  );
}
