import { useMemo } from "react";
import { useNavigate } from "react-router-dom";
import {
  Radio,
  MessageSquare,
  Video,
  Mic,
  Image,
  FileText,
  CircleCheck,
  StickyNote,
  Timer,
  Headphones,
  type LucideIcon,
} from "lucide-react";
import { cn } from "@/lib/utils";
import { useLiveLatestChild } from "@/hooks/use-particle";
import { useAuthStore } from "@/stores/auth-store";
import {
  particlePath,
  type ParticlePath,
} from "@/lib/particle-path";
import { getInitials } from "@/lib/utils";
import { RelativeTimestamp } from "@/components/relative-timestamp";
import { Avatar, AvatarFallback } from "@/components/ui/avatar";
import { Separator } from "@/components/ui/separator";
import { Progress } from "@/components/ui/progress";
import { Small } from "@/components/ui/typography";
import type { Particle, StreamProperties } from "@/api/types";
import { useNetwork } from "@/hooks/use-networks";
import { useExpiringSoon } from "@/hooks/use-expiring-soon";
import { useStreamParticles } from "@/hooks/use-stream-particles";
import { useStreamAutoplay } from "@/hooks/use-stream-autoplay";

function getParticleTypeIcon(particle: Particle): LucideIcon {
  switch (particle.type) {
    case "text":
      return MessageSquare;
    case "media": {
      const mime = particle.properties.mime_type;
      if (mime.startsWith("video/")) return Video;
      if (mime.startsWith("audio/")) return Mic;
      if (mime.startsWith("image/")) return Image;
      return Video;
    }
    case "file":
      return FileText;
    case "quest":
      return CircleCheck;
    case "paper":
      return StickyNote;
    default:
      return Radio;
  }
}

function getMessagePreview(particle: Particle): string {
  switch (particle.type) {
    case "text":
      return particle.properties.content;
    case "media": {
      const mime = particle.properties.mime_type;
      if (mime.startsWith("video/")) return "Video clip";
      if (mime.startsWith("audio/")) return "Voice note";
      if (mime.startsWith("image/")) return "Photo";
      return "Media";
    }
    case "file":
      return particle.properties.filename;
    case "quest":
      return particle.properties.title;
    case "paper":
      return particle.properties.title;
    default:
      return particle.type;
  }
}

function StreamRow({
  particle,
  networkId,
  onClick,
  isSelected,
  shortcutKey,
}: {
  particle: Particle & { type: "stream"; properties: StreamProperties };
  networkId: string;
  onClick: () => 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 expiringSoon = useExpiringSoon(
    particle.last_child_created_at,
    network?.message_retention_hours ?? 24,
  );

  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 initials = 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 getInitials(otherHuman.email);
      }
    }

    if (latestChild) {
      const creator = network?.humans?.find((h) => h.id === latestChild.created_by_human_id);
      if (creator) return getInitials(creator.email);
    }

    return particle.properties.name.slice(0, 2).toUpperCase();
  }, [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 creator = network?.humans?.find((h) => h.id === latestChild.created_by_human_id);
    const name = creator?.email_prefix ?? latestChild.created_by_human_id;
    const capitalized = name.charAt(0).toUpperCase() + name.slice(1);
    return `${capitalized}: `;
  }, [latestChild, userId, isDM, network]);

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

  const TypeIcon = latestChild ? getParticleTypeIcon(latestChild) : Radio;

  return (
    <div
      role="button"
      tabIndex={0}
      onClick={onClick}
      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") onClick(); }}
      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="flex size-5 shrink-0 items-center justify-center rounded bg-white/10 font-mono text-xs text-muted-foreground">
          {shortcutKey}
        </kbd>
      )}
      <Avatar
        className={cn(isUnseen && "ring-2 ring-primary")}
      >
        <AvatarFallback className="bg-primary/10 text-primary font-medium">
          {initials}
        </AvatarFallback>
      </Avatar>
      <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-400" />
                <span className="text-[10px] font-medium text-red-400">{huddleCount}</span>
              </span>
            )}
            {expiringSoon && (
              <Timer className="size-3 text-muted-foreground/60" />
            )}
            {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">
          <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>
  );
}

interface ParticleListViewProps {
  path: ParticlePath;
  selectedIndex?: number | null;
}

/**
 * List of stream particles for a container (network root, folder, etc.).
 */
export function ParticleListView({ path, selectedIndex }: ParticleListViewProps) {
  const { streams, isLoading, networkId } = useStreamParticles(path);
  const navigate = useNavigate();

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

  if (streams.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">
          No recent streams yet. Start a conversation using the keyboard shortcuts below.
        </p>
      </div>
    );
  }

  return (
    <div>
      {streams.map((stream, index) => (
        <div
          key={stream.id}
          ref={index === selectedIndex ? (el) => el?.scrollIntoView({ block: "nearest" }) : undefined}
        >
          <StreamRow
            particle={stream}
            networkId={networkId}
            onClick={() => navigate(`/${networkId}/${stream.id}`)}
            isSelected={index === selectedIndex}
            shortcutKey={index < 9 ? index + 1 : undefined}
          />
          {index < streams.length - 1 && <Separator className="px-4" />}
        </div>
      ))}
    </div>
  );
}
