import {
  Fragment,
  useMemo,
  useRef,
  useEffect,
  memo,
  createElement,
} from 'react';
import { Headphones, Radio, FolderIcon } from 'lucide-react';
import { cn, getInitials } from '@/lib/utils';
import { useLiveLatestChild } from '@/hooks/use-particle';
import { useAuthStore } from '@/stores/auth-store';
import { particlePath } from '@/lib/particle-path';
import { resolveHumanDisplay } from '@/lib/humans';
import { RelativeTimestamp } from '@/components/relative-timestamp';
import { HumanAvatar } from '@/components/human-avatar';
import { Separator } from '@/components/ui/separator';
import { Progress } from '@/components/ui/progress';
import { Small } from '@/components/ui/typography';
import { Button } from '@/components/ui/button';
import {
  isParticleDeleted,
  type Particle,
  type StreamProperties,
} from '@/api/types';
import { useNetwork } from '@/hooks/use-networks';
import { useStreamAutoplay } from '@/hooks/use-stream-autoplay';
import { useDownloadUrl } from '@/hooks/use-download-url';
import { getMessagePreview, getParticleTypeIcon } from '@/lib/particle-display';
import { StreamContextMenu } from '@/features/particles/stream-context-menu';

type StreamParticle = Particle & {
  type: 'stream';
  properties: StreamProperties;
};

function VideoThumbnail({
  objectId,
  isUnseen,
}: {
  objectId: string;
  isUnseen: boolean;
}) {
  const { data: url } = useDownloadUrl(objectId);
  return (
    <div
      className={cn(
        'size-8 shrink-0 overflow-hidden rounded-md bg-muted',
        isUnseen && 'ring-2 ring-primary',
      )}
    >
      {url && (
        <video
          // Seek ~15 frames in so we skip any initial black/fade-in frames
          src={`${url}#t=0.5`}
          muted
          playsInline
          preload="metadata"
          className="h-full w-full object-cover"
        />
      )}
    </div>
  );
}

const StreamRow = memo(function StreamRow({
  particle,
  networkId,
  onOpen,
  isSelected,
  shortcutKey,
}: {
  particle: StreamParticle;
  networkId: string;
  onOpen: (particleId: string) => void;
  isSelected?: boolean;
  shortcutKey?: number;
}) {
  const streamPath = particlePath(networkId, [particle.id]);
  const { latestChild } = useLiveLatestChild(streamPath);
  const user = useAuthStore((s) => s.user);
  const userId = user?.id ?? '';
  const network = useNetwork(networkId);

  useStreamAutoplay(latestChild, particle, networkId, network ?? undefined);

  const hasActiveHuddle =
    particle.huddle_active_participants &&
    particle.huddle_active_participants.length > 0;
  const huddleCount = particle.huddle_active_participants?.length ?? 0;

  const isDM =
    particle.visible_to.length === 2 &&
    particle.visible_to.every((v) => v.startsWith('human:'));

  const avatar = useMemo(() => {
    if (isDM) {
      const otherEntry = particle.visible_to.find(
        (v) => v !== `human:${userId}`,
      );
      if (otherEntry) {
        const otherId = otherEntry.replace('human:', '');
        const otherHuman = network?.humans?.find((h) => h.id === otherId);
        if (otherHuman) {
          return {
            initials: getInitials(otherHuman.email),
            avatarObjectId: otherHuman.avatar_object_id ?? null,
          };
        }
      }
    }

    if (latestChild) {
      const creator = network?.humans?.find(
        (h) => h.id === latestChild.created_by_human_id,
      );
      if (creator) {
        return {
          initials: getInitials(creator.email),
          avatarObjectId: creator.avatar_object_id ?? null,
        };
      }
    }

    return {
      initials: particle.properties.name.slice(0, 2).toUpperCase(),
      avatarObjectId: null,
    };
  }, [
    isDM,
    particle.visible_to,
    particle.properties.name,
    userId,
    latestChild,
    network,
  ]);

  const isUnseen = useMemo(() => {
    if (!latestChild) return false;
    const latestChildTimestamp = latestChild.created_at.getTime();
    const userPlaybackPosition =
      particle.playback_markers?.[userId]?.getTime() ?? 0;
    return latestChildTimestamp > userPlaybackPosition;
  }, [latestChild, particle.playback_markers, userId]);

  const senderPrefix = useMemo(() => {
    if (!latestChild) return null;
    const isCurrentUser = latestChild.created_by_human_id === userId;
    if (isDM) {
      return isCurrentUser ? 'You: ' : null;
    }
    // Group stream
    if (isCurrentUser) return 'You: ';
    const { displayName } = resolveHumanDisplay(
      latestChild.created_by_human_id,
      network?.humans,
    );
    const capitalized =
      displayName.charAt(0).toUpperCase() + displayName.slice(1);
    return `${capitalized}: `;
  }, [latestChild, userId, isDM, network]);

  const subtitle = latestChild
    ? getMessagePreview(latestChild)
    : particle.properties.name;

  // Rendered via createElement below: a call-result used directly as a JSX tag
  // is flagged as a dynamically-created component.
  const typeIcon = latestChild ? getParticleTypeIcon(latestChild) : Radio;

  const videoThumbObjectId =
    latestChild &&
    !isParticleDeleted(latestChild) &&
    latestChild.type === 'media' &&
    latestChild.properties.mime_type.startsWith('video/')
      ? latestChild.properties.object_id
      : null;

  return (
    <div
      role="button"
      tabIndex={0}
      onClick={() => onOpen(particle.id)}
      onKeyDown={(e) => {
        if (e.key === 'Enter' || e.key === ' ') onOpen(particle.id);
      }}
      className={cn(
        'flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer transition-colors hover:bg-accent',
        isSelected && 'bg-accent',
        hasActiveHuddle && 'bg-gradient-to-r from-red-500/10 to-transparent',
      )}
    >
      {shortcutKey && (
        <kbd className="bg-muted text-muted-foreground flex size-5 shrink-0 items-center justify-center rounded font-mono text-xs">
          {shortcutKey}
        </kbd>
      )}
      {videoThumbObjectId ? (
        <VideoThumbnail objectId={videoThumbObjectId} isUnseen={!!isUnseen} />
      ) : (
        <HumanAvatar
          className={cn(isUnseen && 'ring-2 ring-primary')}
          avatarObjectId={avatar.avatarObjectId}
          initials={avatar.initials}
          fallbackClassName="bg-primary/10 text-primary font-medium"
        />
      )}
      <div className="min-w-0 flex-1">
        <div className="flex items-center justify-between gap-2">
          <p
            className={cn(
              'truncate text-sm',
              isUnseen
                ? 'font-semibold text-foreground'
                : 'font-medium text-muted-foreground',
            )}
          >
            {particle.properties.name}
          </p>
          <div className="flex shrink-0 items-center gap-1.5">
            {hasActiveHuddle && (
              <span className="flex items-center gap-1 rounded-full bg-red-500/15 px-1.5 py-0.5">
                <Headphones className="size-3 text-red-600 dark:text-red-400" />
                <span className="text-[10px] font-medium text-red-600 dark:text-red-400">
                  {huddleCount}
                </span>
              </span>
            )}
            {latestChild && (
              <Small
                className={cn(
                  'shrink-0',
                  isUnseen ? 'text-primary' : 'text-muted-foreground',
                )}
              >
                <RelativeTimestamp date={latestChild.created_at} />
              </Small>
            )}
          </div>
        </div>
        <div className="flex items-center gap-1">
          {createElement(typeIcon, {
            className: cn(
              'size-3.5 shrink-0',
              isUnseen ? 'text-foreground' : 'text-muted-foreground',
            ),
          })}
          <Small
            className={cn(
              'truncate',
              isUnseen
                ? 'text-foreground font-medium'
                : 'text-muted-foreground font-normal',
            )}
          >
            {senderPrefix && (
              <span className="text-muted-foreground">{senderPrefix}</span>
            )}
            {subtitle}
          </Small>
        </div>
      </div>
      {isUnseen && <span className="size-2 shrink-0 rounded-full bg-primary" />}
    </div>
  );
});

const FolderRow = memo(function FolderRow({
  particle,
  networkId,
  onOpen,
  isSelected,
  shortcutKey,
}: {
  particle: Particle & { type: 'folder' };
  networkId: string;
  onOpen: (particleId: string) => void;
  isSelected?: boolean;
  shortcutKey?: number;
}) {
  const network = useNetwork(networkId);
  const creator = resolveHumanDisplay(
    particle.created_by_human_id,
    network?.humans,
  );

  return (
    <div
      role="button"
      tabIndex={0}
      onClick={() => onOpen(particle.id)}
      onKeyDown={(e) => {
        if (e.key === 'Enter' || e.key === ' ') onOpen(particle.id);
      }}
      className={cn(
        'flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer transition-colors hover:bg-accent',
        isSelected && 'bg-accent',
      )}
    >
      {shortcutKey && (
        <kbd className="bg-muted text-muted-foreground flex size-5 shrink-0 items-center justify-center rounded font-mono text-xs">
          {shortcutKey}
        </kbd>
      )}
      <span className="flex size-8 shrink-0 items-center justify-center rounded-md bg-amber-500/15">
        <FolderIcon className="size-4 text-amber-500" />
      </span>
      <div className="min-w-0 flex-1">
        <p className="truncate text-sm font-medium text-foreground">
          {particle.properties.name}
        </p>
        <Small className="text-muted-foreground font-normal">
          Folder · {creator.displayName}
        </Small>
      </div>
      <Small className="shrink-0 text-muted-foreground">
        <RelativeTimestamp date={particle.created_at} />
      </Small>
    </div>
  );
});

const LeafRow = memo(function LeafRow({
  particle,
  networkId,
  onOpen,
  isSelected,
  shortcutKey,
}: {
  particle: Particle;
  networkId: string;
  onOpen: (particleId: string) => void;
  isSelected?: boolean;
  shortcutKey?: number;
}) {
  const network = useNetwork(networkId);
  const creator = resolveHumanDisplay(
    particle.created_by_human_id,
    network?.humans,
  );
  const typeIcon = getParticleTypeIcon(particle);
  const deleted = isParticleDeleted(particle);
  const taskDone = particle.type === 'task' && particle.properties.done;

  return (
    <div
      role="button"
      tabIndex={0}
      onClick={() => onOpen(particle.id)}
      onKeyDown={(e) => {
        if (e.key === 'Enter' || e.key === ' ') onOpen(particle.id);
      }}
      className={cn(
        'flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer transition-colors hover:bg-accent',
        isSelected && 'bg-accent',
      )}
    >
      {shortcutKey && (
        <kbd className="bg-muted text-muted-foreground flex size-5 shrink-0 items-center justify-center rounded font-mono text-xs">
          {shortcutKey}
        </kbd>
      )}
      {createElement(typeIcon, {
        className: cn(
          'size-4 shrink-0 text-muted-foreground',
          taskDone && 'text-emerald-500',
        ),
      })}
      <div className="min-w-0 flex-1">
        <p
          className={cn(
            'truncate text-sm',
            deleted || taskDone
              ? 'text-muted-foreground line-through'
              : 'text-foreground',
          )}
        >
          {getMessagePreview(particle)}
        </p>
        <Small className="text-muted-foreground font-normal">
          {creator.displayName}
        </Small>
      </div>
      <Small className="shrink-0 text-muted-foreground">
        <RelativeTimestamp date={particle.created_at} />
      </Small>
    </div>
  );
});

interface ParticleChildrenListProps {
  items: Particle[];
  networkId: string;
  isLoading: boolean;
  /** Open (navigate into / select) a particle by id. */
  onOpen: (particleId: string) => void;
  selectedIndex?: number | null;
  /** Render 1–9 shortcut badges next to the first nine rows. */
  showShortcuts?: boolean;
  emptyMessage?: string;
  /** When true, render a footer that invokes onLoadMore. */
  canLoadMore?: boolean;
  onLoadMore?: () => void;
}

/**
 * Browsable list of a container's children, any particle type. Used by the
 * network root and folder views.
 */
export function ParticleChildrenList({
  items,
  networkId,
  isLoading,
  onOpen,
  selectedIndex,
  showShortcuts = true,
  emptyMessage = 'Nothing here yet. Create something using the keyboard shortcuts below.',
  canLoadMore,
  onLoadMore,
}: ParticleChildrenListProps) {
  const rowRefs = useRef<Array<HTMLDivElement | null>>([]);

  useEffect(() => {
    if (
      selectedIndex !== null &&
      selectedIndex !== undefined &&
      selectedIndex >= 0
    ) {
      rowRefs.current[selectedIndex]?.scrollIntoView({ block: 'nearest' });
    }
  }, [selectedIndex]);

  if (isLoading) {
    return <Progress />;
  }

  if (items.length === 0) {
    return (
      <div className="mx-auto flex h-full max-w-sm flex-col items-center justify-center gap-2 px-4 text-center">
        <Radio className="text-muted-foreground size-8" />
        <p className="text-muted-foreground text-sm">{emptyMessage}</p>
      </div>
    );
  }

  return (
    <div>
      {items.map((item, index) => {
        const rowProps = {
          networkId,
          onOpen,
          isSelected: index === selectedIndex,
          shortcutKey: showShortcuts && index < 9 ? index + 1 : undefined,
        };
        const row = (
          <div
            ref={(el) => {
              rowRefs.current[index] = el;
            }}
          >
            {item.type === 'stream' ? (
              <StreamRow particle={item} {...rowProps} />
            ) : item.type === 'folder' ? (
              <FolderRow particle={item} {...rowProps} />
            ) : (
              <LeafRow particle={item} {...rowProps} />
            )}
            {index < items.length - 1 && <Separator className="px-4" />}
          </div>
        );
        return item.type === 'stream' ? (
          <StreamContextMenu
            key={item.id}
            particle={item}
            networkId={networkId}
          >
            {row}
          </StreamContextMenu>
        ) : (
          <Fragment key={item.id}>{row}</Fragment>
        );
      })}
      {canLoadMore && onLoadMore && (
        <div className="flex justify-center p-3">
          <Button variant="ghost" size="sm" onClick={onLoadMore}>
            Load more
          </Button>
        </div>
      )}
    </div>
  );
}
