import {
  createContext,
  ReactNode,
  useCallback,
  useContext,
  useMemo,
  useRef,
  useState,
} from 'react';
import { formatDate } from 'date-fns';
import {
  AlertTriangle,
  ArrowUp,
  ChevronDown,
  ChevronUp,
  Clock,
  Link as LinkLucide,
  PieChart,
  Play,
  TreePine,
} from 'lucide-react';
import AutoSizer from 'react-virtualized-auto-sizer';
import { useQuery } from 'urql';
import { GraphQLHighlight } from '@/components/common/GraphQLSDLBlock';
import { NotFoundContent } from '@/components/common/not-found-content';
import { Page, TargetLayout } from '@/components/layouts/target';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { CardDescription } from '@/components/ui/card';
import { CopyIconButton } from '@/components/ui/copy-icon-button';
import { Meta } from '@/components/ui/meta';
import { SubPageLayoutHeader } from '@/components/ui/page-content-layout';
import { ResizableHandle, ResizablePanel, ResizablePanelGroup } from '@/components/ui/resizable';
import { ScrollArea } from '@/components/ui/scroll-area';
import {
  Sheet,
  SheetContent,
  SheetDescription,
  SheetFooter,
  SheetHeader,
  SheetTitle,
} from '@/components/ui/sheet';
import { Skeleton } from '@/components/ui/skeleton';
import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from '@/components/ui/tooltip';
import { FragmentType, graphql, useFragment } from '@/gql';
import { useClipboard } from '@/lib/hooks';
import { cn } from '@/lib/utils';
import { Link, useNavigate } from '@tanstack/react-router';
import { useWidthSync, WidthSyncProvider } from './traces/target-traces-width';

const rootTraceColor = 'rgb(244, 183, 64)';

interface TraceAttribute {
  name: string;
  value: string;
}

function TraceView(props: {
  rootSpan: SpanFragmentWithChildren;
  serviceNames: string[];
  totalTraceDuration: bigint;
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
  traceId: string;
}) {
  const [width] = useWidthSync();
  const [highlightedServiceName, setHighlightedServiceName] = useState<string | null>(null);

  const timestamps = splitNanosecondsToMsIntervals(props.totalTraceDuration);

  return (
    <div className="flex h-full flex-col">
      <div className="border-neutral-5 sticky top-0 z-10 border-b">
        <div className="text-neutral-12 flex w-full items-center text-xs">
          <div className="h-12 shrink-0 py-2" style={{ width }}>
            <div className="pl-4">
              <div className="font-medium">Timeline</div>
              <div className="text-neutral-10 text-xs">Spans and details</div>
            </div>
          </div>
          <div className="h-12 grow pr-8">
            <div className="relative size-full">
              <div className="absolute left-0 top-6 -translate-x-1/2 text-center">
                {formatMsTimestamp(timestamps[0])}
              </div>
              <div className="absolute bottom-0 left-0 h-2 w-px bg-zinc-800" />
              <div className="absolute left-[25%] top-6 -translate-x-1/2 text-center">
                {formatMsTimestamp(timestamps[1])}
              </div>
              <div className="absolute bottom-0 left-[25%] h-2 w-px -translate-x-1/2 bg-zinc-800" />
              <div className="absolute left-[50%] top-6 -translate-x-1/2 text-center">
                {formatMsTimestamp(timestamps[2])}
              </div>
              <div className="absolute bottom-0 left-[50%] h-2 w-px -translate-x-1/2 bg-zinc-800" />
              <div className="absolute left-[75%] top-6 -translate-x-1/2 text-center">
                {formatMsTimestamp(timestamps[3])}
              </div>
              <div className="absolute bottom-0 left-[75%] h-2 w-px -translate-x-1/2 bg-zinc-800" />
              <div className="absolute right-0 top-6 translate-x-1/2 text-center">
                {formatMsTimestamp(timestamps[4])}
              </div>
              <div className="absolute bottom-0 right-0 h-2 w-px -translate-x-1/2 bg-zinc-800" />
            </div>
          </div>
        </div>
      </div>
      <ScrollArea className="grow">
        <div>
          <TraceTree
            leftPanelWidth={width}
            rootSpan={props.rootSpan}
            highlightedServiceName={highlightedServiceName}
            serviceNames={props.serviceNames}
            organizationSlug={props.organizationSlug}
            projectSlug={props.projectSlug}
            targetSlug={props.targetSlug}
            traceId={props.traceId}
          />
        </div>
      </ScrollArea>
      {props.serviceNames && (
        <div className="sticky bottom-0 z-10 px-2 py-4">
          <div className="text-neutral-10 flex flex-wrap items-center justify-center gap-6 text-xs">
            {props.serviceNames.map(serviceName => (
              <div
                key={serviceName}
                className="hover:text-neutral-12 flex cursor-pointer items-center gap-2"
                onMouseEnter={() => setHighlightedServiceName(serviceName)}
                onMouseLeave={() => setHighlightedServiceName(null)}
              >
                <div
                  className="size-2"
                  style={{
                    backgroundColor: stringToHSL(serviceName),
                  }}
                />
                <div>{serviceName}</div>
              </div>
            ))}
          </div>
        </div>
      )}
    </div>
  );
}

function TreeIcon(props: {
  level: number;
  /**
   * Decides whether or not to draw the └[]
   */
  hasParent: boolean;
  /**
   * Decides whether or not to draw
   */
  isLeaf: boolean;
  /**
   * Wheter or not to draw ├
   */
  isLastChild: boolean;
  childrenCount: number;
  isCollapsed: boolean;
  lines: boolean[];
  onClick?: () => void;
}) {
  const levelWidth = 16;
  const base = 30;
  const width = base + props.level * levelWidth;

  const leftSideEdgeStart = (props.level - 1) * levelWidth + 12;
  const leftSideEdgeEnd = leftSideEdgeStart + 15;

  const rectLeft = 2 + props.level * levelWidth;

  return (
    <svg
      width={width}
      height="100%"
      preserveAspectRatio="xMidYMid meet"
      className="shrink"
      onClick={props.onClick}
    >
      {/* left-side line */}
      {props.hasParent ? (
        <line x1={leftSideEdgeStart} y1="16" x2={leftSideEdgeEnd} y2="16" stroke="currentColor" />
      ) : null}

      {/* bottom line */}
      {props.isLeaf || props.isCollapsed ? null : (
        <line x1={rectLeft + 10} x2={rectLeft + 10} y1="16" y2="32" stroke="currentColor" />
      )}

      {/* leaf span */}
      {props.isLeaf ? (
        <circle cx={props.level * 16 + 12} cy="16" r="3" fill="currentColor" />
      ) : (
        // number block
        <>
          <rect
            x={rectLeft}
            y="8"
            width="20"
            height="16"
            rx="3px"
            ry="3px"
            fill={props.isCollapsed ? 'currentColor' : 'black'}
            stroke="currentColor"
          />
          <text
            x={rectLeft + 10}
            y="20"
            style={{ fontSize: 10 }}
            textAnchor="middle"
            fontWeight={props.isCollapsed ? 700 : 500}
            fill={props.isCollapsed ? 'white' : 'currentColor'}
          >
            {props.childrenCount}
          </text>
        </>
      )}

      {/* this line is the vertical line (for each parent groups) */}
      {props.lines.map((line, index) =>
        line ? (
          <line
            x1={16 * (index + 1) - 4}
            x2={16 * (index + 1) - 4}
            y1="0"
            y2={index === props.level - 1 && props.isLastChild ? 16 : 32}
            stroke="currentColor"
            key={`${props.level}_${index}`}
          />
        ) : null,
      )}
    </svg>
  );
}

function TabButton(props: { isActive: boolean; onClick(): void; children: ReactNode }) {
  return (
    <button
      className={cn(
        'border-b-2 p-2',
        props.isActive ? 'border-[#2662d8]' : 'hover:border-neutral-5 border-transparent',
      )}
      onClick={props.onClick}
    >
      {props.children}
    </button>
  );
}

function TraceResize(props: { minWidth: number; maxWidth: number }) {
  const [width, setWidth] = useWidthSync();
  const [isDragging, setIsDragging] = useState(false);
  const handleRef = useRef<HTMLDivElement>(null);
  const startPosRef = useRef(0);
  const startWidthRef = useRef(0);
  const { minWidth, maxWidth } = props;

  // Handle the start of dragging
  const handleDragStart = useCallback(
    (clientX: number) => {
      setIsDragging(true);
      startPosRef.current = clientX;
      startWidthRef.current = width;

      // Prevent text selection during drag
      document.body.style.userSelect = 'none';
    },
    [width],
  );

  // Handle dragging
  const handleDrag = useCallback(
    (clientX: number) => {
      if (!isDragging) return;
      const delta = clientX - startPosRef.current;
      let newWidth = startWidthRef.current + delta;
      // Constrain to min/max
      newWidth = Math.min(Math.max(newWidth, minWidth), maxWidth);
      setWidth(newWidth);
    },
    [isDragging, minWidth, maxWidth, setWidth],
  );

  // Handle the end of dragging
  const handleDragEnd = useCallback(() => {
    setIsDragging(false);
    document.body.style.userSelect = '';
  }, []);

  // Pointer event handlers
  const handlePointerDown = useCallback(
    (e: React.PointerEvent) => {
      e.preventDefault();
      // Set pointer capture on the drag handle element
      if (handleRef.current) {
        handleRef.current.setPointerCapture(e.pointerId);
      }
      handleDragStart(e.clientX);
    },
    [handleDragStart],
  );

  const handlePointerMove = useCallback(
    (e: React.PointerEvent) => {
      if (!isDragging) return;
      e.preventDefault();
      handleDrag(e.clientX);
    },
    [isDragging, handleDrag],
  );

  const handlePointerUp = useCallback(
    (e: React.PointerEvent) => {
      e.preventDefault();
      // Release pointer capture
      if (handleRef.current) {
        handleRef.current.releasePointerCapture(e.pointerId);
      }
      handleDragEnd();
    },
    [handleDragEnd],
  );

  return (
    <div
      className="absolute inset-y-0 z-20 w-[5px] cursor-ew-resize"
      style={{ left: width - 2 }} // Position 2px to the left of the center
      ref={handleRef}
      onPointerDown={handlePointerDown}
      onPointerMove={handlePointerMove}
      onPointerUp={handlePointerUp}
    >
      {/* Invisible wider hit area */}
      <div
        className={cn(
          'bg-neutral-5 absolute inset-y-0 left-[2px] w-px',
          isDragging ? 'bg-neutral-8' : 'hover:bg-neutral-2',
        )}
      />
    </div>
  );
}

function TraceTree(props: {
  highlightedServiceName: string | null;
  rootSpan: SpanFragmentWithChildren;
  leftPanelWidth: number;
  serviceNames: Array<string>;
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
  traceId: string;
}) {
  const rootSpan = useFragment(SpanFragment, props.rootSpan.span);
  const [width] = useWidthSync();
  const minWidth = 175;
  const maxWidth = 450;
  const containerRef = useRef<HTMLDivElement>(null);

  const durationNs = differenceInNanoseconds(rootSpan.endTime, rootSpan.startTime);

  return (
    <div className="relative" ref={containerRef}>
      <TraceResize minWidth={minWidth} maxWidth={maxWidth} />
      <SpanNode
        key={rootSpan.id}
        level={0}
        highlightedServiceName={props.highlightedServiceName}
        totalDurationNs={durationNs}
        leftPanelWidth={width}
        span={props.rootSpan}
        parentSpan={null}
        groupLines={[]}
        parentColor={null}
        color={rootTraceColor}
        serviceName={null}
        isLastChild={false}
        organizationSlug={props.organizationSlug}
        projectSlug={props.projectSlug}
        targetSlug={props.targetSlug}
        traceId={props.traceId}
      />
    </div>
  );
}

type SpanNodeProps = {
  highlightedServiceName: string | null;
  level: number;
  totalDurationNs: bigint;
  leftPanelWidth: number;
  span: SpanFragmentWithChildren;
  parentSpan: SpanFragmentWithChildren | null;
  groupLines: boolean[];
  color: string;
  parentColor: string | null;
  serviceName: string | null;
  isLastChild: boolean;
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
  traceId: string;
};

function countChildren(spans: SpanFragmentWithChildren[]): number {
  return spans.reduce((acc, span) => acc + countChildren(span.children), spans.length);
}

type NodeElementProps = {
  leftPositionPercentage: number;
  widthPercentage: number;
  isNearRightEdge: boolean;
  durationStr: string;
  color: string;
};

function NodeElement(props: NodeElementProps) {
  return (
    <div
      className={cn('relative z-20 block h-6 min-w-px select-none rounded-sm')}
      style={{
        left: `min(${props.leftPositionPercentage}%, 100% - 1px)`,
        width: `${props.widthPercentage}%`,
        backgroundColor: props.color,
      }}
    >
      <div
        className="absolute top-1/2 flex -translate-y-1/2 items-center whitespace-nowrap px-[4px] font-mono leading-none"
        style={{
          fontSize: '11px',
          ...(props.isNearRightEdge ? { right: '6px' } : { left: 'calc(100% + 6px)' }),
        }}
      >
        {props.durationStr}
      </div>
    </div>
  );
}

function SpanNode(props: SpanNodeProps) {
  const span = useFragment(SpanFragment, props.span.span);

  const [collapsed, setCollapsed] = useState(false);
  const leftPositionPercentage = roundFloatToTwoDecimals(
    (nanosecondsToMilliseconds(props.span.startNs) /
      nanosecondsToMilliseconds(props.totalDurationNs)) *
      100,
  );

  const widthPercentage = roundFloatToTwoDecimals(
    (nanosecondsToMilliseconds(props.span.durationNs) /
      nanosecondsToMilliseconds(props.totalDurationNs)) *
      100,
  );

  const isNearRightEdge = leftPositionPercentage + widthPercentage > 85;
  const activeSpanId = useContext(ActiveSpanIdContext);
  const highlightedEvent = useContext(HighlightedEventContext);

  const isDimmed =
    (typeof props.highlightedServiceName === 'string' &&
      props.highlightedServiceName !==
        span.spanAttributes['hive.gateway.upstream.subgraph.name']) ||
    (activeSpanId && activeSpanId !== span.id) ||
    (highlightedEvent && highlightedEvent.spanId !== span.id);

  const childrenCount = collapsed
    ? countChildren(props.span.children) + 1
    : props.span.children.length;

  const canBeCollapsed = props.span.children.length > 0;
  const parentColor = props.parentColor ?? props.color;

  const hasException = span.events.some(event => event.name === 'exception');

  return (
    <>
      <div
        className={cn(
          'odd:bg-neutral-5/20 hover:bg-neutral-2 pr-8',
          hasException && 'bg-red-900/20 odd:bg-red-900/20 hover:bg-red-900',
          highlightedEvent && highlightedEvent.spanId === span.id && 'bg-red-900 odd:bg-red-900',
        )}
      >
        <div className="relative flex h-8 w-full items-center overflow-hidden">
          <div
            className="relative flex h-8 shrink-0 items-center gap-x-2 overflow-hidden pl-1"
            style={{ width: `${props.leftPanelWidth}px` }}
          >
            <div
              className={cn(
                'text-neutral-10 flex h-8 shrink-0 items-center truncate',
                canBeCollapsed && 'cursor-pointer',
              )}
            >
              <TreeIcon
                key={`tree-icon-${span.id}`}
                isLeaf={props.span.children.length === 0}
                isLastChild={props.isLastChild}
                childrenCount={childrenCount}
                hasParent={!!props.parentSpan}
                level={props.level}
                lines={props.groupLines}
                isCollapsed={collapsed}
                onClick={canBeCollapsed ? () => setCollapsed(collapsed => !collapsed) : undefined}
              />
            </div>
            <div
              className={cn(
                'flex w-full items-center whitespace-nowrap align-middle text-xs',
                isDimmed ? 'text-neutral-10' : 'text-neutral-12',
              )}
            >
              <span className="mr-1">{span.name}</span>
              {hasException && (
                <Badge
                  variant="outline"
                  className="ml-auto mr-1 rounded-sm border-0 bg-red-900/30 px-1 font-mono text-xs font-medium uppercase text-red-400"
                >
                  Error
                </Badge>
              )}
            </div>
            {span.spanAttributes['hive.gateway.upstream.subgraph.name'] ? (
              <div
                className={cn('truncate text-xs', isDimmed ? 'text-neutral-8' : 'text-neutral-10')}
              >
                {span.spanAttributes['hive.gateway.upstream.subgraph.name']}
              </div>
            ) : null}
          </div>
          <div className="relative w-full">
            <Tooltip disableHoverableContent delayDuration={100}>
              <TooltipTrigger asChild>
                <Link
                  className={cn(
                    'relative flex h-full grow cursor-pointer items-center overflow-hidden',
                    isDimmed ? 'opacity-25' : '',
                  )}
                  to="/$organizationSlug/$projectSlug/$targetSlug/trace/$traceId"
                  params={{
                    organizationSlug: props.organizationSlug,
                    projectSlug: props.projectSlug,
                    targetSlug: props.targetSlug,
                    traceId: props.traceId,
                  }}
                  search={{ activeSpanId: span.id }}
                >
                  <NodeElement
                    color={props.color}
                    isNearRightEdge={isNearRightEdge}
                    leftPositionPercentage={leftPositionPercentage}
                    widthPercentage={widthPercentage}
                    durationStr={formatNanoseconds(props.span.durationNs)}
                  />
                </Link>
              </TooltipTrigger>
              <TooltipContent
                side="bottom"
                className="text-neutral-11 overflow-hidden rounded-lg p-2 text-xs shadow-lg sm:min-w-[200px]"
              >
                {/* Content */}
                <div className="space-y-3">
                  <div className="grid grid-cols-2 gap-y-2">
                    <div className="text-neutral-10">Duration</div>
                    <div className="text-right font-mono">
                      <span>{formatNanoseconds(props.span.durationNs)}</span>
                    </div>

                    <div className="text-neutral-10">Started At</div>
                    <div className="text-right font-mono">
                      {formatNanoseconds(props.span.startNs)}
                    </div>

                    <div className="text-neutral-10">% of Total</div>
                    <div className="text-right font-mono">{props.span.percentageOfTotal}%</div>

                    <div className="col-span-2">
                      {/* Timeline visualization */}
                      <div>
                        <div className="bg-neutral-5 h-[2px] w-full overflow-hidden">
                          <div
                            className="h-full"
                            style={{
                              width: `${props.span.percentageOfTotal}%`,
                              backgroundColor: rootTraceColor,
                            }}
                          />
                        </div>
                      </div>
                    </div>

                    {props.span.percentageOfParentSpan === null ? null : (
                      <>
                        <div className="text-neutral-10">% of Parent</div>
                        <div className="text-right font-mono">
                          {props.span.percentageOfParentSpan}%
                        </div>

                        <div className="col-span-2">
                          {/* Timeline visualization */}
                          <div>
                            <div className="bg-neutral-5 h-[2px] w-full overflow-hidden">
                              <div
                                className="h-full"
                                style={{
                                  width: `${props.span.percentageOfParentSpan}%`,
                                  backgroundColor: parentColor,
                                }}
                              />
                            </div>
                          </div>
                        </div>
                      </>
                    )}
                  </div>
                </div>
              </TooltipContent>
            </Tooltip>

            {props.span.events.map(event => {
              if (highlightedEvent && event.id !== highlightedEvent.eventId) {
                return null;
              }

              const leftPercentage = roundFloatToTwoDecimals(
                (nanosecondsToMilliseconds(event.timeNs) /
                  nanosecondsToMilliseconds(props.totalDurationNs)) *
                  100,
              );
              const isError = event.name === 'exception';

              return (
                <Tooltip delayDuration={100} key={event.id}>
                  <TooltipTrigger asChild>
                    <Link
                      className={cn(
                        'absolute inset-y-0 z-50 translate-x-[-50%] cursor-pointer px-1',
                      )}
                      style={{ left: `${leftPercentage}%` }}
                      to="/$organizationSlug/$projectSlug/$targetSlug/trace/$traceId"
                      params={{
                        organizationSlug: props.organizationSlug,
                        projectSlug: props.projectSlug,
                        targetSlug: props.targetSlug,
                        traceId: props.traceId,
                      }}
                      search={{ activeSpanId: span.id, activeSpanTab: 'events' }}
                    >
                      <div className="relative h-full">
                        <div
                          className={cn(
                            'absolute inset-y-0 w-0.5',
                            isError ? 'bg-red-500' : 'bg-yellow-500',
                          )}
                        >
                          <div
                            className={cn(
                              'absolute left-[-3px] top-[-2px] size-2',
                              isError ? 'bg-red-500' : 'bg-yellow-500',
                            )}
                          />
                        </div>
                      </div>
                    </Link>
                  </TooltipTrigger>
                  <TooltipContent
                    side="bottom"
                    className="text-neutral-11 overflow-hidden rounded-lg border-none p-1 text-xs shadow-lg sm:min-w-[200px]"
                  >
                    <div className="z-20">
                      <ExceptionTeaser
                        type={String(event.attributes['exception.type'] ?? '')}
                        message={String(event.attributes['exception.message'] ?? '')}
                        stacktrace={String(event.attributes['exception.stacktrace'] ?? '')}
                        name={event.name}
                      />
                    </div>
                  </TooltipContent>
                </Tooltip>
              );
            })}
          </div>
        </div>
      </div>
      {collapsed
        ? null
        : props.span.children.length
          ? props.span.children.map((childSpan, i, arr) => {
              // eslint-disable-next-line react-hooks/rules-of-hooks
              const uchildSpan = useFragment(SpanFragment, childSpan.span);

              const serviceName: string | null =
                uchildSpan.spanAttributes['hive.gateway.upstream.subgraph.name'] ??
                props.serviceName ??
                null;

              const isLastChild = i === arr.length - 1;
              return (
                <SpanNode
                  key={uchildSpan.id}
                  span={childSpan}
                  highlightedServiceName={props.highlightedServiceName}
                  leftPanelWidth={props.leftPanelWidth}
                  totalDurationNs={props.totalDurationNs}
                  level={props.level + 1}
                  parentSpan={props.span}
                  groupLines={
                    props.isLastChild
                      ? // remove the last line if it's the last span from the group
                        props.groupLines.slice(0, -1).concat(false, true)
                      : props.groupLines.concat(true)
                  }
                  parentColor={props.color}
                  color={serviceName ? stringToHSL(serviceName) : props.color}
                  serviceName={serviceName}
                  isLastChild={isLastChild}
                  organizationSlug={props.organizationSlug}
                  projectSlug={props.projectSlug}
                  targetSlug={props.targetSlug}
                  traceId={props.traceId}
                />
              );
            })
          : null}
    </>
  );
}

const TraceSheet_TraceFragment = graphql(`
  fragment TraceSheet_TraceFragment on Trace {
    id
    subgraphs
    spans {
      id
      ...SpanFragment
      ...SpanSheet_SpanFragment
    }
  }
`);

type TraceSheetProps = {
  trace: FragmentType<typeof TraceSheet_TraceFragment>;
  activeSpanId: string | null;
  activeSpanTab: string | null;
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
};

type HighlightedEvent = {
  spanId: string;
  eventId: string;
};

const HighlightedEventContext = createContext(null as null | HighlightedEvent);
const ActiveSpanIdContext = createContext(null as null | string);

export function TraceSheet(props: TraceSheetProps) {
  const [activeView, setActiveView] = useState<
    'span-attributes' | 'resource-attributes' | 'events' | 'operation'
  >('span-attributes');
  const trace = useFragment(TraceSheet_TraceFragment, props.trace);

  const [highlightedEvent, setHighlightedEvent] = useState<HighlightedEvent | null>(null);

  const { rootSpan, spansById, events } = useMemo(
    () => createSpanTreeStructure(trace.spans),
    [trace.spans],
  );
  const rootSpanUnmasked = useFragment(SpanFragment, rootSpan.span);
  const spanAttributes: Array<TraceAttribute> = Array.from(
    Object.entries(rootSpanUnmasked.spanAttributes),
  ).map(([name, value]) => ({
    name,
    value: String(value),
  }));

  const resourceAttributes: Array<TraceAttribute> = Array.from(
    Object.entries(rootSpanUnmasked.resourceAttributes),
  ).map(([name, value]) => ({
    name,
    value: String(value),
  }));

  const totalTraceDuration = differenceInNanoseconds(
    rootSpanUnmasked.endTime,
    rootSpanUnmasked.startTime,
  );

  const navigate = useNavigate({
    from: '/$organizationSlug/$projectSlug/$targetSlug/trace/$traceId',
  });

  return (
    <div className="h-full">
      <TooltipProvider>
        <ResizablePanelGroup direction="vertical">
          <ResizablePanel defaultSize={70} minSize={20} maxSize={80}>
            <WidthSyncProvider defaultWidth={251}>
              <HighlightedEventContext.Provider value={highlightedEvent}>
                <ActiveSpanIdContext.Provider value={props.activeSpanId}>
                  <TraceView
                    rootSpan={rootSpan}
                    serviceNames={trace.subgraphs ?? []}
                    totalTraceDuration={totalTraceDuration}
                    organizationSlug={props.organizationSlug}
                    projectSlug={props.projectSlug}
                    targetSlug={props.targetSlug}
                    traceId={trace.id}
                  />
                </ActiveSpanIdContext.Provider>
              </HighlightedEventContext.Provider>
            </WidthSyncProvider>
          </ResizablePanel>
          <ResizableHandle withHandle />
          <ResizablePanel defaultSize={30} minSize={10} maxSize={80}>
            <div className="flex h-full flex-col">
              <div className="border-neutral-5 sticky top-0 z-10 border-b">
                <div className="flex w-full gap-x-4 px-2 text-xs font-medium">
                  <TabButton
                    isActive={activeView === 'span-attributes'}
                    onClick={() => setActiveView('span-attributes')}
                  >
                    <div className="flex items-center gap-x-2">
                      <div>Attributes</div>
                      <div>
                        <Badge
                          variant="secondary"
                          className="rounded-md px-2 py-0.5 text-[10px] font-thin"
                        >
                          {spanAttributes.length}
                        </Badge>
                      </div>
                    </div>
                  </TabButton>
                  <TabButton
                    isActive={activeView === 'resource-attributes'}
                    onClick={() => setActiveView('resource-attributes')}
                  >
                    <div className="flex items-center gap-x-2">
                      <div>Resource Attributes</div>
                      <div>
                        <Badge
                          variant="secondary"
                          className="rounded-md px-2 py-0.5 text-[10px] font-thin"
                        >
                          {resourceAttributes.length}
                        </Badge>
                      </div>
                    </div>
                  </TabButton>
                  <TabButton
                    isActive={activeView === 'events'}
                    onClick={() => setActiveView('events')}
                  >
                    <div className="flex items-center gap-x-2">
                      <div>Events</div>
                      <div>
                        <Badge
                          variant="secondary"
                          className="rounded-md px-2 py-0.5 text-[10px] font-thin"
                        >
                          {events.length}
                        </Badge>
                      </div>
                    </div>
                  </TabButton>
                  <TabButton
                    isActive={activeView === 'operation'}
                    onClick={() => setActiveView('operation')}
                  >
                    <div className="flex items-center gap-x-2">
                      <div>GraphQL Operation</div>
                    </div>
                  </TabButton>
                </div>
              </div>
              <ScrollArea className="relative grow">
                <div className="h-full">
                  {activeView === 'span-attributes' ? (
                    <div>
                      {spanAttributes.length > 0 ? (
                        spanAttributes.map(attr => (
                          <AttributeRow
                            attributeKey={attr.name}
                            key={attr.name}
                            value={attr.value}
                          />
                        ))
                      ) : (
                        <div className="py-4 text-center">
                          <AlertTriangle className="text-neutral-10 mx-auto mb-2 size-6" />
                          <p className="text-neutral-10 text-xs">
                            No attributes found for this trace
                          </p>
                        </div>
                      )}
                    </div>
                  ) : null}
                  {activeView === 'resource-attributes' ? (
                    <div>
                      {resourceAttributes.length > 0 ? (
                        resourceAttributes.map(attr => (
                          <AttributeRow
                            attributeKey={attr.name}
                            key={attr.name}
                            value={attr.value}
                          />
                        ))
                      ) : (
                        <div className="py-4 text-center">
                          <AlertTriangle className="text-neutral-10 mx-auto mb-2 size-6" />
                          <p className="text-neutral-10 text-xs">
                            No resource attributes found for this trace
                          </p>
                        </div>
                      )}
                    </div>
                  ) : null}
                  {activeView === 'events' ? (
                    <div className="p-4">
                      <div className="space-y-2">
                        {!events.length ? (
                          <div className="text-neutral-8 text-sm">
                            No events occured during this trace.
                          </div>
                        ) : (
                          events.map(event => (
                            <Link
                              to="/$organizationSlug/$projectSlug/$targetSlug/trace/$traceId"
                              params={{
                                organizationSlug: props.organizationSlug,
                                projectSlug: props.projectSlug,
                                targetSlug: props.targetSlug,
                                traceId: trace.id,
                              }}
                              search={{ activeSpanId: event.spanId, activeSpanTab: 'events' }}
                              onMouseOver={() =>
                                setHighlightedEvent({
                                  spanId: event.spanId,
                                  eventId: event.id,
                                })
                              }
                              onMouseLeave={() => {
                                setHighlightedEvent(null);
                              }}
                              className="mb-2 block"
                              key={event.id}
                            >
                              <ExceptionTeaser
                                type={String(event.attributes['exception.type'] ?? '')}
                                message={String(event.attributes['exception.message'] ?? '')}
                                stacktrace={String(event.attributes['exception.stacktrace'] ?? '')}
                                name={event.name}
                              />
                            </Link>
                          ))
                        )}
                      </div>
                    </div>
                  ) : null}
                  {activeView === 'operation' ? (
                    <div className="absolute inset-y-0 w-full">
                      <GraphQLHighlight
                        height="100%"
                        options={{
                          fontSize: 10,
                          minimap: { enabled: false },
                        }}
                        code={rootSpanUnmasked.spanAttributes['graphql.document']}
                      />
                    </div>
                  ) : null}
                </div>
              </ScrollArea>
            </div>
          </ResizablePanel>
        </ResizablePanelGroup>
      </TooltipProvider>
      {props.activeSpanId && (
        <SpanSheet
          span={trace.spans.find(trace => trace.id === props.activeSpanId) ?? null}
          computedSpanMetrics={spansById.get(props.activeSpanId) ?? null}
          onClose={() =>
            navigate({
              to: '/$organizationSlug/$projectSlug/$targetSlug/trace/$traceId',
              search: {},
            })
          }
          organizationSlug={props.organizationSlug}
          projectSlug={props.projectSlug}
          targetSlug={props.targetSlug}
          traceId={trace.id}
          activeTab={props.activeSpanTab}
        />
      )}
    </div>
  );
}

const TargetInsightsNewPageContent_TraceQuery = graphql(/* GraphQL */ `
  query TargetInsightsNewPageContent_TraceQuery(
    $targetSelector: TargetSelectorInput!
    $traceId: ID!
  ) {
    target(reference: { bySelector: $targetSelector }) {
      id
      trace(traceId: $traceId) {
        ...TraceSheet_TraceFragment
        id
        operationName
        duration
        success
        timestamp
        spans {
          id
          name
          parentId
          ...SpanFragment
        }
      }
    }
  }
`);

function TargetInsightsNewPageContent(props: {
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
  traceId: string;
  activeSpanId: string | null;
  activeSpanTab: string | null;
}) {
  const [result] = useQuery({
    query: TargetInsightsNewPageContent_TraceQuery,
    variables: {
      targetSelector: {
        organizationSlug: props.organizationSlug,
        projectSlug: props.projectSlug,
        targetSlug: props.targetSlug,
      },
      traceId: props.traceId,
    },
  });

  const isFetching = result.fetching || result.stale;
  const trace = result.data?.target?.trace;

  return (
    <div className="flex h-full flex-col space-y-4 pt-6">
      <Meta title={`Trace ${props.traceId}`} />
      <SubPageLayoutHeader
        subPageTitle={
          <span className="flex items-center">
            <Link
              to="/$organizationSlug/$projectSlug/$targetSlug/traces"
              params={{
                organizationSlug: props.organizationSlug,
                projectSlug: props.projectSlug,
                targetSlug: props.targetSlug,
              }}
            >
              Traces
            </Link>{' '}
            <span className="text-neutral-10 inline-block px-2 italic">/</span>{' '}
            {trace ? (
              <>
                {trace.operationName ?? <span className="text-neutral-10">{'<unknown>'}</span>}
                <span className="text-neutral-10 ml-2 font-mono font-normal">
                  {trace.id.substring(0, 4)}
                </span>
              </>
            ) : (
              <Skeleton className="inline-block h-5 w-[150px]" />
            )}
          </span>
        }
        description={
          <>
            <CardDescription>
              Trace ID:{' '}
              {trace?.id ? (
                <>
                  <span className="font-mono"> {trace.id}</span>
                  <CopyIconButton value={trace.id} label="Copy Trace ID" />
                </>
              ) : (
                <Skeleton className="inline-block h-4 w-[200px]" />
              )}
            </CardDescription>
            {trace && (
              <div className="mt-2 flex items-center gap-3 text-xs">
                <div className="flex items-center gap-1">
                  <Clock className="text-neutral-10 size-3" />
                  <span className="text-neutral-11">
                    {formatNanoseconds(BigInt(trace.duration))}
                  </span>
                </div>
                <Badge
                  variant="outline"
                  className={cn(
                    'rounded-sm border-0 px-1 font-medium uppercase',
                    trace.success ? 'bg-green-900/30 text-green-400' : 'bg-red-900/30 text-red-400',
                  )}
                >
                  {trace.success ? 'Ok' : 'Error'}
                </Badge>
                <span className="text-neutral-11 font-mono uppercase">
                  {formatDate(trace.timestamp, 'MMM dd HH:mm:ss')}
                </span>
              </div>
            )}
          </>
        }
      />
      {trace && (
        <TraceSheet
          organizationSlug={props.organizationSlug}
          projectSlug={props.projectSlug}
          targetSlug={props.targetSlug}
          trace={trace}
          activeSpanId={props.activeSpanId}
          activeSpanTab={props.activeSpanTab}
        />
      )}
      {!trace && !isFetching && (
        <>
          <Meta title="Trace Not found" />
          <NotFoundContent heading="Trace not found." subheading="This trace does not exist." />
        </>
      )}
    </div>
  );
}

export function TargetTracePage(props: {
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
  traceId: string;
  activeSpanId: string | null;
  activeSpanTab: string | null;
}) {
  return (
    <>
      <TargetLayout
        organizationSlug={props.organizationSlug}
        projectSlug={props.projectSlug}
        targetSlug={props.targetSlug}
        page={Page.Traces}
        className="flex flex-col"
      >
        <div className="flex flex-1 flex-col">
          <AutoSizer disableWidth>
            {size => (
              <div className="w-full" style={{ height: size.height }}>
                <TargetInsightsNewPageContent {...props} />
              </div>
            )}
          </AutoSizer>
        </div>
      </TargetLayout>
    </>
  );
}

const SpanFragment = graphql(/* GraphQL */ `
  fragment SpanFragment on Span {
    id
    name
    spanAttributes
    resourceAttributes
    parentId
    startTime
    endTime
    events {
      date
      name
      attributes
    }
  }
`);

type ComputedSpanMetrics = {
  durationNs: bigint;
  startNs: bigint;
  percentageOfTotal: string;
  percentageOfParentSpan: string | null;
};

type SpanEvent = {
  id: string;
  spanId: string;
  name: string;
  attributes: Record<string, unknown>;
  type: string;
  timeNs: bigint;
};

type SpanFragmentWithChildren = {
  id: string;
  span: FragmentType<typeof SpanFragment>;
  children: Array<SpanFragmentWithChildren>;
  events: Array<SpanEvent>;
} & ComputedSpanMetrics;

function createSpanTreeStructure(fragments: Array<FragmentType<typeof SpanFragment>>): {
  rootSpan: SpanFragmentWithChildren;
  spansById: ReadonlyMap<string, SpanFragmentWithChildren>;
  events: ReadonlyArray<SpanEvent>;
} {
  const spansById = new Map</* id */ string, SpanFragmentWithChildren>();
  const events: Array<SpanEvent> = [];

  let rootSpan: SpanFragmentWithChildren | null = null;
  for (const fragment of fragments) {
    // eslint-disable-next-line react-hooks/rules-of-hooks
    const ufragment = useFragment(SpanFragment, fragment);

    const fragmentWithChildren: SpanFragmentWithChildren = {
      id: ufragment.id,
      span: fragment,
      children: [],
      durationNs: differenceInNanoseconds(ufragment.endTime, ufragment.startTime),
      startNs: 0n,
      percentageOfTotal: '',
      percentageOfParentSpan: null,
      events: [],
    };

    spansById.set(ufragment.id, fragmentWithChildren);
    if (ufragment.parentId == null) {
      rootSpan = fragmentWithChildren;
      rootSpan.percentageOfTotal = '100';
    }
  }

  if (!rootSpan) {
    throw new Error('No root found.');
  }

  // eslint-disable-next-line react-hooks/rules-of-hooks
  const uroot = useFragment(SpanFragment, rootSpan.span);
  const startNS = parseRFC3339ToEpochNanos(uroot.startTime);

  let eventIdCounter = 0;

  for (const item of spansById.values()) {
    // eslint-disable-next-line react-hooks/rules-of-hooks
    const uitem = useFragment(SpanFragment, item.span);

    for (const event of uitem.events) {
      eventIdCounter++;
      const spanEvent: SpanEvent = {
        id: uitem.id + '_' + String(eventIdCounter),
        spanId: uitem.id,
        name: event.name,
        attributes: event.attributes,
        type: 'exception',
        timeNs: parseRFC3339ToEpochNanos(event.date) - startNS,
      };
      events.push(spanEvent);
      item.events.push(spanEvent);
    }

    if (!uitem.parentId) {
      continue;
    }
    const parent = spansById.get(uitem.parentId);
    if (!parent) {
      throw new Error('Missing parent.');
    }

    parent.children.push(item);
    item.startNs = parseRFC3339ToEpochNanos(uitem.startTime) - startNS;
    if (item.percentageOfTotal === '') {
      item.percentageOfTotal = (
        (nanosecondsToMilliseconds(item.durationNs) /
          nanosecondsToMilliseconds(rootSpan.durationNs)) *
        100
      ).toFixed(2);
    }
    item.percentageOfParentSpan = (
      (nanosecondsToMilliseconds(item.durationNs) / nanosecondsToMilliseconds(parent.durationNs)) *
      100
    ).toFixed(2);
  }

  for (const item of spansById.values()) {
    item.children.sort((a, b) => {
      if (a.startNs < b.startNs) {
        return -1;
      }
      if (a.startNs > b.startNs) {
        return 1;
      }
      return 0;
    });
  }

  return { rootSpan, spansById, events };
}

export function formatNanoseconds(nsBigInt: bigint) {
  const TEN_THOUSAND_NS = 10_000n;

  if (nsBigInt === 0n) {
    return '0ms';
  }

  if (nsBigInt < TEN_THOUSAND_NS) {
    return `${nsBigInt}ns`;
  }

  const hundredthsOfMs = nsBigInt / TEN_THOUSAND_NS;
  const msValue = Number(hundredthsOfMs) / 100.0;
  return `${msValue.toFixed(2)}ms`;
}

function parseRFC3339ToEpochNanos(datetime: string) {
  const match = datetime.match(
    /^(\d{4})-(\d{2})-(\d{2})T(\d{2}):(\d{2}):(\d{2})(?:\.(\d{1,9}))?Z$/,
  );

  if (!match) {
    throw new Error('Invalid RFC 3339 datetime string.');
  }

  const [, year, month, day, hour, minute, second, fraction = '0'] = match;

  // Pad fraction to nanoseconds (9 digits)
  const nanoStr = (fraction + '000000000').slice(0, 9);
  const nanoseconds = parseInt(nanoStr, 10);

  // Use Date.UTC to get milliseconds (integer part of timestamp)
  const milliseconds = Date.UTC(+year, +month - 1, +day, +hour, +minute, +second);

  const totalNanoseconds = BigInt(milliseconds) * 1_000_000n + BigInt(nanoseconds);
  return totalNanoseconds;
}

function differenceInNanoseconds(datetime1: string, datetime2: string) {
  const nanos1 = parseRFC3339ToEpochNanos(datetime1);
  const nanos2 = parseRFC3339ToEpochNanos(datetime2);

  return nanos1 - nanos2; // returns a BigInt representing nanoseconds
}

function splitNanosecondsToMsIntervals(nanoseconds: bigint): number[] {
  const intervals: number[] = [0];
  const intervalNs = nanoseconds / 4n;

  for (let i = 0; i < 4; i++) {
    // Convert nanoseconds to milliseconds (with up to 6 decimal places)
    const ms = ((i + 1) * Number(intervalNs)) / 1_000_000;
    intervals.push(ms);
  }

  return intervals;
}

function formatMsTimestamp(timestamp: number) {
  if (timestamp === 0) {
    return '0ms';
  }
  return timestamp.toFixed(2) + 'ms';
}

function stringToHSL(str: string, saturation = 70, lightness = 40) {
  // Simple hash function
  let hash = 0;
  for (let i = 0; i < str.length; i++) {
    hash = str.charCodeAt(i) + ((hash << 5) - hash);
    hash = hash & hash; // Convert to 32bit integer
  }

  // Use hash to generate HSL values
  const hue = Math.abs(hash) % 360;

  return `hsl(${hue}, ${saturation}%, ${lightness}%)`;
}

function nanosecondsToMilliseconds(nsBigInt: bigint) {
  const oneMillion = 1_000_000n;
  const msBigInt = nsBigInt / oneMillion; // BigInt division, truncates remainder

  return Number(msBigInt); // Convert BigInt to Number
}

function roundFloatToTwoDecimals(num: number) {
  return Math.round(num * 100) / 100;
}

const SpanSheet_SpanFragment = graphql(`
  fragment SpanSheet_SpanFragment on Span {
    id
    resourceAttributes
    spanAttributes
    name
    duration
    parentId
    events {
      name
      attributes
      date
    }
  }
`);

type SpanSheetProps = {
  span: FragmentType<typeof SpanSheet_SpanFragment> | null;
  computedSpanMetrics: ComputedSpanMetrics | null;
  onClose: () => void;
  organizationSlug: string;
  projectSlug: string;
  targetSlug: string;
  traceId: string;
  activeTab: string | null;
};

function SpanSheet(props: SpanSheetProps) {
  const span = useFragment(SpanSheet_SpanFragment, props.span);
  const [activeView, setActiveView] = useState<
    'span-attributes' | 'resource-attributes' | 'events' | 'operation'
  >((props.activeTab as 'events') ?? 'span-attributes');
  const clipboard = useClipboard();

  // TODO: maybe loading or not found state???
  if (!span) {
    return null;
  }

  const spanAttributes = Array.from(Object.entries(span.spanAttributes)).map(
    ([key, value]) => ({ key, value }) satisfies { key: string; value: unknown },
  );

  const resourceAttributes = Array.from(Object.entries(span.resourceAttributes)).map(
    ([key, value]) => ({ key, value }) satisfies { key: string; value: unknown },
  );

  return (
    <Sheet open onOpenChange={props.onClose}>
      <SheetContent className="border-neutral-5 text-neutral-12 bg-neutral-1 flex flex-col border-l p-0 md:max-w-[50%]">
        <SheetHeader className="border-neutral-5 relative border-b p-4">
          <div className="flex items-center justify-between">
            <SheetTitle className="text-neutral-12 text-lg font-medium">
              {!span.parentId && 'Root '}Span Details
              <span className="text-neutral-10 ml-2 font-mono font-normal">
                {span.id.substring(0, 4)}
              </span>
              <span className="text-neutral-10 ml-2">{span.name}</span>
            </SheetTitle>
          </div>
          <SheetDescription className="text-neutral-10 mt-1 text-xs">
            Span ID: <span className="font-mono">{span.id}</span>
            <CopyIconButton value={span.id} label="Copy Span ID" />
          </SheetDescription>
          {props.computedSpanMetrics && (
            <div className="grid grid-cols-2 gap-4 pt-3 md:grid-cols-4">
              {/* Duration */}
              <div className="flex items-center space-x-2">
                <Clock className="size-4 text-blue-500" />
                <div>
                  <p className="text-neutral-10 text-xs">Duration</p>
                  <p className="text-sm font-medium">
                    {' '}
                    {formatNanoseconds(props.computedSpanMetrics.durationNs)}
                  </p>
                </div>
              </div>

              {/* Start Time */}
              {props.computedSpanMetrics.startNs !== 0n && (
                <div className="flex items-center space-x-2">
                  <Play className="size-4 text-green-500" />
                  <div>
                    <p className="text-neutral-10 text-xs">Start</p>
                    <p className="text-sm font-medium">
                      {' '}
                      {formatNanoseconds(props.computedSpanMetrics.startNs)}
                    </p>
                  </div>
                </div>
              )}

              {/* Percentage of Total */}
              {props.computedSpanMetrics.percentageOfTotal && (
                <div className="flex items-center space-x-2">
                  <PieChart className="size-4 text-purple-500" />
                  <div>
                    <p className="text-neutral-10 text-xs">% of Total</p>
                    <p className="text-sm font-medium">
                      {' '}
                      {props.computedSpanMetrics.percentageOfTotal}%
                    </p>
                  </div>
                </div>
              )}

              {/* Percentage of Parent */}
              {props.computedSpanMetrics.percentageOfParentSpan && (
                <div className="flex items-center space-x-2">
                  <TreePine className="text-accent size-4" />
                  <div>
                    <p className="text-neutral-10 text-xs">% of Parent</p>
                    <p className="text-sm font-medium">
                      {' '}
                      {props.computedSpanMetrics.percentageOfParentSpan}%
                    </p>
                  </div>
                </div>
              )}
            </div>
          )}
        </SheetHeader>
        <div className="h-full overflow-hidden">
          <div className="flex h-full flex-col">
            <div className="border-neutral-5 sticky top-0 z-10 border-b">
              <div className="flex w-full gap-x-4 px-2 text-xs font-medium">
                <TabButton
                  isActive={activeView === 'span-attributes'}
                  onClick={() => setActiveView('span-attributes')}
                >
                  <div className="flex items-center gap-x-2">
                    <div>Span Attributes</div>
                    <div>
                      <Badge
                        variant="secondary"
                        className="rounded-md px-2 py-0.5 text-[10px] font-thin"
                      >
                        {Array.from(Object.keys(span.spanAttributes)).length}
                      </Badge>
                    </div>
                  </div>
                </TabButton>
                <TabButton
                  isActive={activeView === 'resource-attributes'}
                  onClick={() => setActiveView('resource-attributes')}
                >
                  <div className="flex items-center gap-x-2">
                    <div>Resource Attributes</div>
                    <div>
                      <Badge
                        variant="secondary"
                        className="rounded-md px-2 py-0.5 text-[10px] font-thin"
                      >
                        {resourceAttributes.length}
                      </Badge>
                    </div>
                  </div>
                </TabButton>
                <TabButton
                  isActive={activeView === 'events'}
                  onClick={() => setActiveView('events')}
                >
                  <div className="flex items-center gap-x-2">
                    <div>Events</div>
                    <div>
                      <Badge
                        variant="secondary"
                        className="rounded-md px-2 py-0.5 text-[10px] font-thin"
                      >
                        {span.events.length}
                      </Badge>
                    </div>
                  </div>
                </TabButton>
                {span.spanAttributes['graphql.document'] && (
                  <TabButton
                    isActive={activeView === 'operation'}
                    onClick={() => setActiveView('operation')}
                  >
                    <div className="flex items-center gap-x-2">
                      <div>GraphQL Operation</div>
                    </div>
                  </TabButton>
                )}
              </div>
            </div>
            <div className="flex-1 overflow-y-scroll">
              {activeView === 'span-attributes' && (
                <div>
                  {spanAttributes.length > 0 ? (
                    <div>
                      {spanAttributes.map(attribute => (
                        <AttributeRow
                          key={attribute.key}
                          attributeKey={attribute.key}
                          value={String(attribute.value)}
                        />
                      ))}
                    </div>
                  ) : (
                    <div className="py-4 text-center">
                      <AlertTriangle className="text-neutral-10 mx-auto mb-2 size-6" />
                      <p className="text-neutral-10 text-xs">
                        No span attributes found for this span.
                      </p>
                    </div>
                  )}
                </div>
              )}
              {activeView === 'resource-attributes' && (
                <div>
                  {resourceAttributes.length > 0 ? (
                    <div>
                      {resourceAttributes.map(attribute => (
                        <AttributeRow
                          key={attribute.key}
                          attributeKey={attribute.key}
                          value={String(attribute.value)}
                        />
                      ))}
                    </div>
                  ) : (
                    <div className="py-4 text-center">
                      <AlertTriangle className="text-neutral-10 mx-auto mb-2 size-6" />
                      <p className="text-neutral-10 text-xs">
                        No resource attributes found for this span.
                      </p>
                    </div>
                  )}
                </div>
              )}
              {activeView === 'events' && (
                <div>
                  {span.events.length > 0 ? (
                    <div className="px-1 pt-2">
                      {span.events.map((event, index) => {
                        return (
                          <div className="mb-2" key={`${event.name}_${event.date}_${index}`}>
                            <ExceptionTeaser
                              type={event.attributes['exception.type'] ?? ''}
                              message={event.attributes['exception.message'] ?? ''}
                              stacktrace={event.attributes['exception.stacktrace'] ?? ''}
                              name={event.name}
                            />
                          </div>
                        );
                      })}
                    </div>
                  ) : (
                    <div className="py-4 text-center">
                      <AlertTriangle className="text-neutral-10 mx-auto mb-2 size-6" />
                      <p className="text-neutral-10 text-xs">No events found for this span.</p>
                    </div>
                  )}
                </div>
              )}
              {activeView === 'operation' && (
                <GraphQLHighlight
                  height="100%"
                  options={{
                    fontSize: 10,
                    minimap: { enabled: false },
                  }}
                  code={span.spanAttributes['graphql.document']}
                />
              )}
            </div>
          </div>
        </div>
        <SheetFooter className="mt-auto border-t p-2">
          {span.parentId && (
            <Button variant="ghost" size="sm" asChild>
              <Link
                to="/$organizationSlug/$projectSlug/$targetSlug/trace/$traceId"
                params={{
                  organizationSlug: props.organizationSlug,
                  projectSlug: props.projectSlug,
                  targetSlug: props.targetSlug,
                  traceId: props.traceId,
                }}
                search={{ activeSpanId: span.parentId }}
              >
                <ArrowUp className="mr-2 size-4" /> Show Parent Span
              </Link>
            </Button>
          )}
          <Button variant="ghost" size="sm" onClick={() => clipboard(window.location.href)}>
            <LinkLucide className="mr-2 size-4" /> Share Link
          </Button>
        </SheetFooter>
      </SheetContent>
    </Sheet>
  );
}

type AttributeRowProps = {
  attributeKey: string;
  value: string;
};

function AttributeRow(props: AttributeRowProps) {
  const [isExpanded, setIsExpanded] = useState(false);

  const actionsNode = (
    <span className="text-neutral-12 ml-auto mr-0 flex">
      <CopyIconButton value={props.value} label="Copy attribute value" />
      <TooltipProvider>
        <Tooltip delayDuration={0} disableHoverableContent>
          <TooltipTrigger asChild>
            <Button variant="ghost" size="icon-xs" onClick={() => setIsExpanded(bool => !bool)}>
              {isExpanded ? <ChevronUp size="14" /> : <ChevronDown size="14" />}
            </Button>
          </TooltipTrigger>
          <TooltipContent className="text-xs">{isExpanded ? 'Collapse' : 'Expand'}</TooltipContent>
        </Tooltip>
      </TooltipProvider>
    </span>
  );

  return (
    <div
      key={props.attributeKey}
      className={cn(
        'border-neutral-5 flex items-center justify-between border-b p-3 text-xs last:border-0',
        isExpanded && 'flex-col text-left',
      )}
    >
      <div className={cn('text-neutral-10 flex flex-1 pr-2', isExpanded && 'w-full pr-0')}>
        {props.attributeKey}
        {isExpanded && actionsNode}
      </div>
      <div
        className={cn(
          'text-neutral-12 w-full flex-1 pt-2 font-mono text-[10px]',
          !isExpanded && 'overflow-hidden text-ellipsis text-nowrap pt-0',
        )}
      >
        {props.value}
      </div>
      {!isExpanded && actionsNode}
    </div>
  );
}

function ExceptionTeaser(props: {
  name: string;
  message: string;
  stacktrace: string | null;
  type: string;
}) {
  return (
    <div className="overflow-hidden rounded-md border border-red-800/50 bg-red-900/20">
      <div className="flex items-center justify-between bg-red-900/40 px-3 py-2">
        <span className="font-mono text-xs font-medium text-red-300">{props.type}</span>
        <Badge variant="outline" className="border-red-700 bg-red-900 text-[10px] text-red-300">
          {props.name}
        </Badge>
      </div>
      <div className="p-3 text-xs">
        <p className="text-neutral-11">{props.message}</p>
        {props.stacktrace && (
          <pre className="bg-neutral-1/50 text-neutral-10 mt-2 overflow-x-auto rounded-sm p-2 font-mono text-[10px] leading-tight">
            {props.stacktrace}
          </pre>
        )}
      </div>
    </div>
  );
}
