import { useState, useMemo } from 'react';
import { useParams, useNavigate } from 'react-router-dom';
import { ArrowLeft, Copy, Check } from 'lucide-react';
import { Panel } from '@/components/ui/Panel';
import { Badge } from '@/components/ui/Badge';
import { Spinner } from '@/components/ui/Spinner';
import { EmptyState } from '@/components/ui/EmptyState';
import { JsonViewer } from '@/components/ui/JsonViewer';
import { TraceWaterfall, type Span } from '@/components/charts/TraceWaterfall';
import { useTrace } from '@/hooks/useTrace';

// ---------------------------------------------------------------------------
// 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 : []);

function statusToBadge(s: string): 'ok' | 'error' | 'warn' | 'info' {
  const low = s.toLowerCase();
  if (low === 'error' || low === 'unhealthy') return 'error';
  if (low === 'warn' || low === 'degraded') return 'warn';
  if (low === 'ok' || low === 'healthy') return 'ok';
  return 'info';
}

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

export default function OtelTraceDetailPage() {
  const { traceId } = useParams<{ traceId: string }>();
  const navigate = useNavigate();
  const traceQuery = useTrace(traceId ?? '');
  const [selectedSpan, setSelectedSpan] = useState<Span | null>(null);
  const [copied, setCopied] = useState(false);

  // --- Parse trace data ---
  const traceData = asRecord(traceQuery.data);

  const spans: Span[] = useMemo(() => {
    const rawSpans = arr(traceData.spans ?? traceData.data);
    if (rawSpans.length === 0) return [];

    // Find the earliest start time to compute offsets
    let minStart = Infinity;
    const parsed = rawSpans.map((s: unknown) => {
      const rec = asRecord(s);
      const startMs = num(rec.start_time_ms ?? rec.startTime ?? rec.start_time ?? rec.timestamp);
      if (startMs < minStart) minStart = startMs;
      return { rec, startMs };
    });

    return parsed.map(({ rec, startMs }) => ({
      spanId: str(rec.span_id ?? rec.spanId),
      parentSpanId: str(rec.parent_span_id ?? rec.parentSpanId) || undefined,
      operationName: str(rec.operation_name ?? rec.operationName ?? rec.name),
      serviceName: str(rec.service_name ?? rec.serviceName ?? rec.service),
      startTime: startMs - (minStart === Infinity ? 0 : minStart),
      duration: num(rec.duration_ms ?? rec.duration),
      status: str(rec.status ?? 'ok'),
      attributes: rec.attributes && typeof rec.attributes === 'object'
        ? (rec.attributes as Record<string, unknown>)
        : undefined,
      events: arr(rec.events).map((ev: unknown) => {
        const evRec = asRecord(ev);
        return {
          name: str(evRec.name),
          timestamp: num(evRec.timestamp),
          attributes: evRec.attributes && typeof evRec.attributes === 'object'
            ? (evRec.attributes as Record<string, unknown>)
            : undefined,
        };
      }),
    }));
  }, [traceData]);

  // --- Derived header info ---
  const rootService = useMemo(() => {
    if (spans.length === 0) return '--';
    const root = spans.find((s) => !s.parentSpanId);
    return root?.serviceName || spans[0]?.serviceName || '--';
  }, [spans]);

  const totalDuration = useMemo(() => {
    if (spans.length === 0) return 0;
    return Math.max(...spans.map((s) => s.startTime + s.duration));
  }, [spans]);

  const overallStatus = useMemo(() => {
    if (spans.some((s) => s.status.toLowerCase() === 'error')) return 'error';
    if (spans.some((s) => s.status.toLowerCase() === 'warn')) return 'warn';
    return 'ok';
  }, [spans]);

  const handleCopy = () => {
    if (traceId) {
      navigator.clipboard.writeText(traceId).then(() => {
        setCopied(true);
        setTimeout(() => setCopied(false), 2000);
      });
    }
  };

  if (traceQuery.isLoading) {
    return (
      <div className="flex items-center justify-center py-20">
        <Spinner size="lg" />
      </div>
    );
  }

  if (traceQuery.error || spans.length === 0) {
    return (
      <div className="space-y-4">
        <button
          onClick={() => navigate('/otel')}
          className="inline-flex items-center gap-1.5 text-sm text-text-secondary hover:text-text-primary transition-colors"
        >
          <ArrowLeft className="w-4 h-4" />
          Back to Observability
        </button>
        <EmptyState
          title="Trace not found"
          description={`No data available for trace ${traceId ?? 'unknown'}.`}
        />
      </div>
    );
  }

  return (
    <div className="space-y-6">
      {/* Header */}
      <div className="flex flex-col gap-3">
        <button
          onClick={() => navigate('/otel')}
          className="inline-flex items-center gap-1.5 text-sm text-text-secondary hover:text-text-primary transition-colors w-fit"
        >
          <ArrowLeft className="w-4 h-4" />
          Back to Observability
        </button>

        <div className="flex flex-wrap items-center gap-4">
          <div className="flex items-center gap-2">
            <span className="font-mono text-lg text-text-primary select-all">
              {traceId}
            </span>
            <button
              onClick={handleCopy}
              className="text-text-muted hover:text-text-primary transition-colors"
              title="Copy trace ID"
            >
              {copied ? (
                <Check className="w-4 h-4 text-accent-green" />
              ) : (
                <Copy className="w-4 h-4" />
              )}
            </button>
          </div>

          <span className="text-sm text-text-secondary">{rootService}</span>
          <span className="text-sm text-text-secondary">
            {totalDuration.toFixed(1)}ms
          </span>
          <span className="text-sm text-text-secondary">
            {spans.length} span{spans.length !== 1 ? 's' : ''}
          </span>
          <Badge status={statusToBadge(overallStatus)}>{overallStatus}</Badge>
        </div>
      </div>

      {/* Main content */}
      <div className="grid grid-cols-1 lg:grid-cols-3 gap-4">
        {/* Waterfall */}
        <div className="lg:col-span-2">
          <Panel title="Trace Waterfall">
            <div className="overflow-x-auto">
              <TraceWaterfall
                spans={spans}
                onSpanClick={setSelectedSpan}
                selectedSpanId={selectedSpan?.spanId}
              />
            </div>
          </Panel>
        </div>

        {/* Span detail */}
        <div className="lg:col-span-1">
          <Panel title="Span Detail">
            {selectedSpan ? (
              <div className="space-y-4 text-sm">
                <div>
                  <p className="text-text-muted text-xs uppercase tracking-wide mb-1">
                    Operation
                  </p>
                  <p className="text-text-primary font-medium">
                    {selectedSpan.operationName}
                  </p>
                </div>

                <div className="grid grid-cols-2 gap-3">
                  <div>
                    <p className="text-text-muted text-xs uppercase tracking-wide mb-1">
                      Service
                    </p>
                    <p className="text-text-primary">
                      {selectedSpan.serviceName}
                    </p>
                  </div>
                  <div>
                    <p className="text-text-muted text-xs uppercase tracking-wide mb-1">
                      Duration
                    </p>
                    <p className="text-text-primary">
                      {selectedSpan.duration.toFixed(1)}ms
                    </p>
                  </div>
                  <div>
                    <p className="text-text-muted text-xs uppercase tracking-wide mb-1">
                      Status
                    </p>
                    <Badge status={statusToBadge(selectedSpan.status)}>
                      {selectedSpan.status}
                    </Badge>
                  </div>
                  <div>
                    <p className="text-text-muted text-xs uppercase tracking-wide mb-1">
                      Span ID
                    </p>
                    <p className="text-text-primary font-mono text-xs">
                      {selectedSpan.spanId}
                    </p>
                  </div>
                </div>

                {/* Attributes */}
                {selectedSpan.attributes &&
                  Object.keys(selectedSpan.attributes).length > 0 && (
                    <div>
                      <p className="text-text-muted text-xs uppercase tracking-wide mb-2">
                        Attributes
                      </p>
                      <div className="border border-border rounded-md overflow-hidden">
                        <table className="w-full text-xs">
                          <tbody>
                            {Object.entries(selectedSpan.attributes).map(
                              ([key, value]) => (
                                <tr
                                  key={key}
                                  className="border-b border-border last:border-0"
                                >
                                  <td className="px-2 py-1.5 text-text-secondary font-mono whitespace-nowrap">
                                    {key}
                                  </td>
                                  <td className="px-2 py-1.5 text-text-primary">
                                    {typeof value === 'object' ? (
                                      <JsonViewer data={value} collapsed />
                                    ) : (
                                      String(value)
                                    )}
                                  </td>
                                </tr>
                              ),
                            )}
                          </tbody>
                        </table>
                      </div>
                    </div>
                  )}

                {/* Events */}
                {selectedSpan.events && selectedSpan.events.length > 0 && (
                  <div>
                    <p className="text-text-muted text-xs uppercase tracking-wide mb-2">
                      Events
                    </p>
                    <div className="space-y-2">
                      {selectedSpan.events.map((ev, i) => (
                        <div
                          key={i}
                          className="bg-surface border border-border rounded-md px-3 py-2"
                        >
                          <p className="text-text-primary font-medium text-xs">
                            {ev.name}
                          </p>
                          {ev.timestamp > 0 && (
                            <p className="text-text-muted text-xs mt-0.5">
                              +{ev.timestamp.toFixed(1)}ms
                            </p>
                          )}
                          {ev.attributes &&
                            Object.keys(ev.attributes).length > 0 && (
                              <div className="mt-1">
                                <JsonViewer data={ev.attributes} collapsed />
                              </div>
                            )}
                        </div>
                      ))}
                    </div>
                  </div>
                )}
              </div>
            ) : (
              <p className="text-text-muted text-sm py-8 text-center">
                Click a span in the waterfall to view its details.
              </p>
            )}
          </Panel>
        </div>
      </div>
    </div>
  );
}
