import {
	BookMarked,
	CircleDot,
	FolderCode,
	GalleryVertical,
	GitPullRequest,
	LoaderCircle,
	UserRound,
	TrendingUp,
	ShieldCheck,
	Shield,
	ShieldPlus,
	Megaphone,
} from 'lucide-solid';
import clsx from 'clsx';
import { A } from '@solidjs/router';
import { createQuery } from '../lib/atproto-query';
import { For, Show, createEffect, createMemo, createSignal, onCleanup, type Component, type JSX } from 'solid-js';

import { Avatar, ErrorState, LoadingState, StateBadge } from '../components/common';
import { RepoCard } from '../components/repo';
import { listFollowRecords } from '../lib/api/graph';
import { resolveActor } from '../lib/api/identity';
import { listRepoRecords, type RepoRecord } from '../lib/api/repos';
import { useAuth } from '../lib/auth';
import { useLiveEvents, type LiveEvent } from '../lib/live-events';
import { useIssuePreloader, useRepoPreloader } from '../lib/preloading';
import { formatRelativeTime, getErrorMessage, loadRecentRepos, loadRecentIssuesPulls } from '../lib/repo-utils';

const SAMPLE_REPOS: Array<{
	owner: string;
	slug: string;
	description?: string;
	language?: string;
	stars?: number;
	forks?: number;
	openIssues?: number;
	openPRs?: number;
}> = [
	{ owner: 'nekomimi.pet', slug: 'wisp.place-monorepo', description: 'Monorepo for wisp.place. A static site hosting service built on top of the AT Protocol.', language: 'TypeScript', stars: 94, openIssues: 39, openPRs: 23 },
	{ owner: 'mary.my.id', slug: 'atcute', description: 'a collection of lightweight TypeScript packages for AT Protocol, the protocol powering Bluesky', language: 'TypeScript', stars: 101, openIssues: 8 },
	{ owner: 'pds.ls', slug: 'pdsls', description: 'atmosphere explorer', language: 'TypeScript', stars: 491, openIssues: 20, openPRs: 21 },
];

const FALLBACK_ENTRIES = [
	{
		title: 'tail CI logs over SSH',
		link: 'https://blog.tangled.org/ssh',
		summary: 'never leave your terminal to check on CI!',
		updated: '2026-05-28T00:00:00Z',
		author: 'Akshay'
	},
	{
		title: 'combat LLM spam by building a web of trust',
		link: 'https://blog.tangled.org/vouching',
		summary: 'vouching on tangled!',
		updated: '2026-05-01T00:00:00Z',
		author: 'Akshay'
	},
	{
		title: 'we need a federation of forges',
		link: 'https://blog.tangled.org/federation',
		summary: 'git is decentralized, but what of the rest?',
		updated: '2026-04-29T00:00:00Z',
		author: 'Akshay'
	},
	{
		title: 'newsletter 01 — hello!',
		link: 'https://blog.tangled.org/newsletter-01',
		summary: 'kicking off our newsletter!',
		updated: '2026-04-16T00:00:00Z',
		author: 'Anirudh'
	},
	{
		title: 'announcing our €3,8M seed round',
		link: 'https://blog.tangled.org/seed',
		summary: "and more on what's next",
		updated: '2026-03-02T00:00:00Z',
		author: 'Anirudh'
	}
];

const fetchBlogFeed = async (): Promise<any[]> => {
	try {
		const response = await fetch('https://blog.tangled.org/feed.xml');
		if (!response.ok) throw new Error('Failed to fetch');
		const text = await response.text();
		const parser = new DOMParser();
		const xmlDoc = parser.parseFromString(text, 'text/xml');
		const entries = xmlDoc.getElementsByTagName('entry');
		const posts = [];
		for (let i = 0; i < entries.length; i++) {
			const entry = entries[i];
			const title = entry.getElementsByTagName('title')[0]?.textContent || '';
			const updated = entry.getElementsByTagName('updated')[0]?.textContent || '';
			const summary = entry.getElementsByTagName('summary')[0]?.textContent || '';
			const authorName = entry.getElementsByTagName('author')[0]?.getElementsByTagName('name')[0]?.textContent || '';
			
			let href = '';
			const links = entry.getElementsByTagName('link');
			for (let j = 0; j < links.length; j++) {
				const link = links[j];
				if (link.getAttribute('rel') === 'alternate' || !link.getAttribute('rel')) {
					href = link.getAttribute('href') || '';
					break;
				}
			}
			posts.push({
				title,
				link: href || 'https://blog.tangled.org',
				summary,
				updated,
				author: authorName,
			});
		}
		return posts;
	} catch (err) {
		console.warn('CORS or network error fetching blog feed, using fallback', err);
		return FALLBACK_ENTRIES;
	}
};

const formatBlogDate = (dateStr: string) => {
	try {
		const date = new Date(dateStr);
		return date.toLocaleDateString('en-US', {
			month: 'short',
			day: 'numeric',
			year: 'numeric'
		});
	} catch {
		return dateStr;
	}
};

const ANNOUNCEMENT_COLORS = [
	'untangled-home-promo-card-indigo',
	'untangled-home-promo-card-green',
	'untangled-home-promo-card-purple',
	'untangled-home-promo-card-blue',
	'untangled-home-promo-card-amber'
];

const hashStringToIndex = (str: string, count: number): number => {
	let hash = 0;
	for (let i = 0; i < str.length; i++) {
		hash = str.charCodeAt(i) + ((hash << 5) - hash);
	}
	return Math.abs(hash) % count;
};

const AnnouncementCard: Component<{
	title: string;
	link: string;
	summary: string;
	updated: string;
	author: string;
	cardClass: string;
}> = (props) => {
	const formattedDate = () => formatBlogDate(props.updated);
	
	return (
		<div class={clsx('relative overflow-hidden border rounded-sm p-6', props.cardClass)}>
			<div class="pointer-events-none absolute inset-0 bg-[radial-gradient(ellipse_at_bottom_left,rgba(255,255,255,0.25),transparent_70%)]"></div>
			
			<div class="relative z-10 flex flex-col gap-1 text-inherit">
				<div class="flex items-center justify-between text-xs opacity-75 mb-1 text-inherit">
					<span>{props.author}</span>
					<span>{formattedDate()}</span>
				</div>
				<h4 class="font-bold mb-1 text-base leading-snug text-inherit">
					{props.title}
				</h4>
				<p class="text-sm margin-0 opacity-90 text-inherit">
					{props.summary}
				</p>
				<div class="mt-3 flex items-center justify-between">
					<a
						class="no-underline inline-flex items-center gap-1 text-sm font-semibold hover:underline text-inherit"
						href={props.link}
						target="_blank"
						rel="noopener noreferrer"
					>
						Read more &rarr;
					</a>
				</div>
			</div>
		</div>
	);
};

const HOME_ACTIVITY_SOURCES = [
	'sh.tangled.repo.issue:repoDid',
	'sh.tangled.repo.issue:repo',
	'sh.tangled.repo.pull:target.repo',
];

type HomeRepoItem = {
	owner: string;
	slug: string;
	title: string;
	href: string;
	rkey: string;
	repoDid?: string;
	description?: string;
	createdAt?: string;
};

type HomeActivityKind = 'issue' | 'pull' | 'repo';

type HomeActivityItem = {
	id: string;
	kind: HomeActivityKind;
	title: string;
	repoLabel: string;
	href: string;
	uri?: string;
	at?: string;
	body?: string;
	actorDid?: string;
	actorHandle?: string;
};

type FollowingHomeData = {
	actors: Array<{
		did: string;
		handle: string;
		repoCount: number;
	}>;
	activity: HomeActivityItem[];
};

const repoSlug = (repo: RepoRecord): string => repo.value.name?.trim() || repo.rkey;

const repoTimestamp = (repo: HomeRepoItem): number => {
	const timestamp = repo.createdAt ? new Date(repo.createdAt).getTime() : 0;
	return Number.isFinite(timestamp) ? timestamp : 0;
};

const activityTimestamp = (item: HomeActivityItem): number => {
	const timestamp = item.at ? new Date(item.at).getTime() : 0;
	return Number.isFinite(timestamp) ? timestamp : 0;
};

const homeRepoItem = (owner: string, repo: RepoRecord): HomeRepoItem => {
	const slug = repoSlug(repo);
	return {
		owner,
		slug,
		title: `${owner}/${slug}`,
		href: `/${owner}/${slug}`,
		rkey: repo.rkey,
		repoDid: repo.value.repoDid,
		description: repo.value.description,
		createdAt: repo.value.createdAt,
	};
};

const activityLabelForEvent = (event: LiveEvent): Pick<HomeActivityItem, 'kind' | 'title'> => {
	if (event.source.includes('.pull')) {
		return { kind: 'pull', title: 'new pull request' };
	}

	return { kind: 'issue', title: 'new issue' };
};

const eventActivityHref = (repo: HomeRepoItem, event: LiveEvent): string => {
	const collection = event.source.includes('.pull') ? 'pulls' : 'issues';
	return `${repo.href}/${collection}/${encodeURIComponent(event.sourceRecord)}`;
};

const fetchFollowingHomeData = async (viewerDid: string): Promise<FollowingHomeData> => {
	const follows = await listFollowRecords(viewerDid);
	const resolved = await Promise.all(
		follows.slice(0, 8).map(async (follow) => {
			try {
				const actor = await resolveActor(follow.value.subject);
				const repos = await listRepoRecords(actor).catch(() => []);
				return {
					follow,
					actor,
					repos,
				};
			} catch {
				return null;
			}
		}),
	);

	const actors = resolved
		.filter((item): item is NonNullable<typeof item> => Boolean(item))
		.map((item) => ({
			did: item.actor.did,
			handle: item.actor.handle,
			repoCount: item.repos.length,
		}));

	const activity = resolved
		.filter((item): item is NonNullable<typeof item> => Boolean(item))
		.flatMap((item) =>
			item.repos.map((repo) => {
				const repoItem = homeRepoItem(item.actor.handle, repo);
				return {
					id: `following-repo:${repo.uri}`,
					kind: 'repo' as const,
					title: 'repository published',
					repoLabel: repoItem.title,
					href: repoItem.href,
					at: repoItem.createdAt,
					body: repoItem.description,
					actorDid: item.actor.did,
					actorHandle: item.actor.handle,
				};
			}),
		)
		.sort((left, right) => activityTimestamp(right) - activityTimestamp(left))
		.slice(0, 8);

	return { actors, activity };
};

export const HomePage: Component = () => {
	const auth = useAuth();
	const live = useLiveEvents();
	const issuePreloader = useIssuePreloader();
	const recentRepos = createMemo(loadRecentRepos);
	const recentIssuesPulls = createMemo(loadRecentIssuesPulls);



	const ownReposQuery = createQuery(() => ({
		queryKey: ['own-repos', auth.currentDid()],
		enabled: Boolean(auth.currentDid()),
		queryFn: async () => {
			const actor = await resolveActor(auth.currentDid()!);
			const records = await listRepoRecords(actor);
			return { actor, records };
		},
	}));

	const followingQuery = createQuery(() => ({
		queryKey: ['home-following', auth.currentDid()],
		enabled: Boolean(auth.currentDid()),
		queryFn: async () => fetchFollowingHomeData(auth.currentDid()!),
	}));

	const [vouchedHandles, setVouchedHandles] = createSignal<string[]>([]);

	const vouchSuggestionsQuery = createQuery(() => ({
		queryKey: ['vouch-suggestions'],
		queryFn: async () => {
			const handles = ['nekomimi.pet', 'mary.my.id', 'juliet.paris'];
			const resolved = await Promise.all(
				handles.map(async (handle) => {
					try {
						const actor = await resolveActor(handle);
						return {
							did: actor.did,
							handle: actor.handle,
						};
					} catch {
						return {
							did: `did:placeholder:${handle}`,
							handle,
						};
					}
				})
			);
			return resolved;
		}
	}));

	const blogQuery = createQuery(() => ({
		queryKey: ['blog-feed'],
		queryFn: fetchBlogFeed,
	}));


	const ownRepoItems = createMemo(() => {
		const data = ownReposQuery.data;
		if (!data) return [];
		return data.records
			.map((repo) => homeRepoItem(data.actor.handle, repo))
			.sort((left, right) => repoTimestamp(right) - repoTimestamp(left));
	});

	const currentUserHandle = () => ownReposQuery.data?.actor.handle || '';
	const currentUserDid = () => auth.currentDid() || '';

	const repoByDid = createMemo(() => {
		const repos = new Map<string, HomeRepoItem>();
		for (const repo of ownRepoItems()) {
			if (repo.repoDid) repos.set(repo.repoDid, repo);
		}
		return repos;
	});

	createEffect(() => {
		if (!auth.currentDid()) {
			live.clear();
			return;
		}

		if (ownReposQuery.isLoading) {
			return;
		}

		const subjects = ownRepoItems()
			.map((repo) => repo.repoDid)
			.filter((repoDid): repoDid is string => Boolean(repoDid));

		if (subjects.length === 0) {
			live.clear();
			return;
		}

		live.subscribe({
			subjects,
			sources: HOME_ACTIVITY_SOURCES,
		});

		onCleanup(() => {
			live.clear();
		});
	});



	const activityItems = createMemo<HomeActivityItem[]>(() => {
		const repos = repoByDid();
		const liveItems = live.events()
			.map((event): HomeActivityItem | null => {
				const repo = repos.get(event.subject);
				if (!repo) return null;
				const label = activityLabelForEvent(event);
				return {
					id: `live:${event.sourceRecord}:${event.receivedAt}`,
					...label,
					repoLabel: repo.title,
					href: eventActivityHref(repo, event),
					uri: event.sourceRecord,
					at: event.receivedAt,
					actorDid: currentUserDid(),
					actorHandle: currentUserHandle(),
				};
			})
			.filter((item): item is HomeActivityItem => Boolean(item));

		const repoItems: HomeActivityItem[] = ownRepoItems().map((repo) => ({
			id: `repo:${repo.owner}/${repo.rkey}`,
			kind: 'repo' as const,
			title: 'repository published',
			repoLabel: repo.title,
			href: repo.href,
			at: repo.createdAt,
			body: repo.description,
			actorDid: currentUserDid(),
			actorHandle: currentUserHandle(),
		}));

		return [...liveItems, ...repoItems]
			.sort((left, right) => activityTimestamp(right) - activityTimestamp(left))
			.slice(0, 8);
	});

	return (
		<div class="untangled-home-page">
			<section class="untangled-home-workspace">
				<main class="untangled-home-feed">
					<div class="untangled-home-feed-header">
						<h2 class="untangled-home-feed-title">
							<GalleryVertical class="size-5" />
							activity
						</h2>
					</div>

					<Show
						when={auth.currentDid()}
						fallback={<HomeFeedEmpty title="Sign in for repo activity" body="Issues, pull requests, and repos from your account will appear here." />}
					>
						<Show
							when={!ownReposQuery.isLoading}
							fallback={<HomeFeedLoading />}
						>
							<Show
								when={!ownReposQuery.error}
								fallback={<ErrorState message={getErrorMessage(ownReposQuery.error)} />}
							>
								<Show
									when={activityItems().length > 0}
									fallback={<HomeFeedEmpty title="No repo activity yet" body="New repo, issue, and pull request activity will land here." />}
								>
									<div class="untangled-home-activity-list">
										<For each={activityItems()}>
											{(item, index) => <ActivityRow item={item} index={index()} />}
										</For>
									</div>
								</Show>
							</Show>
						</Show>
					</Show>
				</main>

				<aside class="untangled-home-side untangled-home-side-right flex flex-col gap-6">
					{/* Recent Repos */}
					<div class="flex flex-col gap-3 w-full">
						<HomeSectionHeader icon={<BookMarked class="size-5 text-gray-500" />} title="recent" />
						<Show
							when={recentRepos().length > 0}
							fallback={<HomeEmpty label="No recent repos." />}
						>
							<div class="flex flex-col gap-3">
								<For each={recentRepos().slice(0, 5)}>
									{(repo) => (
										<RepoCard
											href={`/${repo.owner}/${repo.slug}`}
											owner={repo.owner}
											name={repo.slug}
											description={repo.description}
											isFork={repo.isFork}
											language={repo.language}
											stars={repo.stars}
											openIssues={repo.openIssues}
											openPRs={repo.openPRs}
											compact
										/>
									)}
								</For>
							</div>
						</Show>
					</div>

					{/* Recent Issues / PRs */}
					<div class="flex flex-col gap-3 w-full">
						<HomeSectionHeader icon={<CircleDot class="size-5" />} title="recent issues / prs" />
						<Show
							when={recentIssuesPulls().length > 0}
							fallback={<HomeEmpty label="No recent issues or pull requests." />}
						>
							<div class="untangled-home-compact-list">
								<For each={recentIssuesPulls().slice(0, 5)}>
									{(item) => {
										const preloadProps = issuePreloader(item.repoLabel, item.kind, item.uri, item.number);

										return (
											<A href={item.href} class="untangled-home-repo-row" {...preloadProps}>
												<div class="text-sm font-semibold text-black dark:text-white truncate">
													{item.title}{' '}
													<span class="text-gray-500 dark:text-gray-400 font-normal">
														#{item.uri.split('/').pop()}
													</span>
												</div>
												<div class="mt-2 flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400 min-w-0">
													<StateBadge state={item.state} kind={item.kind} />
													<span class="truncate min-w-0">
														{item.author} · {item.repoLabel}
													</span>
												</div>
											</A>
										);
									}}
								</For>
							</div>
						</Show>
					</div>
				</aside>
			</section>

			<section class="untangled-home-below">
				<div class="untangled-home-lower-grid">
					{/* Left sidebar announcements */}
					<aside class="untangled-home-side untangled-home-promos-column">
						{/* Announcements Section */}
						<div class="flex flex-col gap-3 w-full">
							<HomeSectionHeader icon={<Megaphone class="size-5" />} title="announcements" />
							<div class="untangled-home-announcements-grid">
								<Show when={!blogQuery.isLoading} fallback={<LoadingState label="Loading announcements..." />}>
									<For each={blogQuery.data?.slice(0, 5) ?? []}>
										{(post) => {
											const colorIndex = hashStringToIndex(post.title, ANNOUNCEMENT_COLORS.length);
											const cardClass = ANNOUNCEMENT_COLORS[colorIndex];
											return (
												<AnnouncementCard
													title={post.title}
													link={post.link}
													summary={post.summary}
													updated={post.updated}
													author={post.author}
													cardClass={cardClass}
												/>
											);
										}}
									</For>
								</Show>
							</div>
						</div>
					</aside>

					<section class="untangled-home-wide-section untangled-home-lower-left">
						<HomeSectionHeader icon={<UserRound class="size-5" />} title="timeline" />
						<Show
							when={auth.currentDid()}
							fallback={<HomeEmpty label="Sign in to see followed repo activity." />}
						>
							<Show
								when={!followingQuery.isLoading}
								fallback={<LoadingState label="Loading followed repos..." />}
							>
								<Show
									when={!followingQuery.error}
									fallback={<ErrorState message={getErrorMessage(followingQuery.error)} />}
								>
									<Show
										when={(followingQuery.data?.activity.length ?? 0) > 0}
										fallback={<HomeEmpty label="No followed repo activity yet." />}
									>
										<div class="untangled-home-activity-list">
											<For each={followingQuery.data?.activity ?? []}>
												{(item, index) => <ActivityRow item={item} index={index()} />}
											</For>
										</div>
									</Show>
								</Show>
							</Show>
						</Show>
					</section>

					<aside class="untangled-home-side flex flex-col gap-6 untangled-home-lower-right">
						<div class="flex flex-col gap-6 w-full untangled-home-sticky-wrapper">
							<section class="untangled-home-wide-section">
								<HomeSectionHeader icon={<TrendingUp class="size-5" />} title="trending" />
								<div class="flex flex-col gap-3">
									<For each={SAMPLE_REPOS}>
										{(repo) => (
											<RepoCard
												href={`/${repo.owner}/${repo.slug}`}
												owner={repo.owner}
												name={repo.slug}
												description={repo.description}
												language={repo.language}
												stars={repo.stars}
												forks={repo.forks}
												openIssues={repo.openIssues}
												compact
											/>
										)}
									</For>
								</div>
							</section>

							{/* Suggested (Vouches) Section */}
							<div class="flex flex-col gap-3 w-full">
								<header class="untangled-home-section-header flex justify-between items-center w-full">
									<div class="flex items-center gap-3">
										<ShieldPlus class="size-5" />
										<h2>suggested</h2>
									</div>
									<Show when={auth.currentDid()}>
										<A href={`/${ownReposQuery.data?.actor.handle || ownReposQuery.data?.actor.did || ''}?tab=vouches`} class="text-sm font-normal hover:underline text-gray-500 dark:text-gray-400">
											view all &rarr;
										</A>
									</Show>
								</header>
								<div class="flex flex-col gap-4 bg-white dark:bg-gray-800 p-4 border border-gray-200 dark:border-gray-700 shadow-sm rounded-sm">
									<Show when={!vouchSuggestionsQuery.isLoading} fallback={<LoadingState label="Loading suggestions..." />}>
										<For each={vouchSuggestionsQuery.data ?? []}>
											{(suggestion) => {
												const isVouched = () => vouchedHandles().includes(suggestion.handle);
												const toggleVouch = () => {
													if (!auth.currentDid()) {
														alert('Please sign in to vouch for users.');
														return;
													}
													if (isVouched()) {
														setVouchedHandles(prev => prev.filter(h => h !== suggestion.handle));
													} else {
														setVouchedHandles(prev => [...prev, suggestion.handle]);
													}
												};
												return (
													<div class="flex items-center gap-3">
														<A href={`/${suggestion.handle}`}>
															<Avatar did={suggestion.did} size="size-10" />
														</A>
														<div class="flex flex-col min-w-0 flex-1">
															<A href={`/${suggestion.handle}`} class="text-sm font-medium dark:text-white hover:underline truncate">
																{suggestion.handle}
															</A>
															<span class="text-xs text-gray-500 dark:text-gray-400 truncate">
																&nbsp;
															</span>
														</div>
														<div class="shrink-0">
															<button
																type="button"
																onClick={toggleVouch}
																class={isVouched() ? 'btn-create text-xs px-2.5 py-1.5' : 'btn text-xs px-2.5 py-1.5'}
															>
																<Show when={isVouched()} fallback={<><Shield class="size-3.5 mr-1 inline" /> vouch</>}>
																	<ShieldCheck class="size-3.5 mr-1 inline" /> vouched
																</Show>
															</button>
														</div>
													</div>
												);
											}}
										</For>
									</Show>
								</div>
							</div>
						</div>
					</aside>
				</div>
			</section>
		</div>
	);
};

const HomeSectionHeader: Component<{ icon: JSX.Element; title: string }> = (props) => (
	<header class="untangled-home-section-header">
		{props.icon}
		<h2>{props.title}</h2>
	</header>
);

const HomeEmpty: Component<{ label: string }> = (props) => (
	<div class="untangled-home-empty">{props.label}</div>
);

const HomeFeedEmpty: Component<{ title: string; body: string }> = (props) => (
	<div class="untangled-home-feed-empty">
		<FolderCode class="size-8" />
		<h3>{props.title}</h3>
		<p>{props.body}</p>
	</div>
);

const HomeFeedLoading: Component = () => (
	<div class="untangled-home-feed-empty">
		<LoaderCircle class="size-8 animate-spin" />
		<h3>Loading activity</h3>
		<p>Checking your repos.</p>
	</div>
);

const ActivityRow: Component<{ item: HomeActivityItem; index: number }> = (props) => {
	const repoUrl = () => `/${props.item.repoLabel}`;
	const actorUrl = () => (props.item.actorHandle ? `/${props.item.actorHandle}` : '#');
	const preloadRepo = useRepoPreloader();
	const issuePreloader = useIssuePreloader();

	const actionText = () => {
		if (props.item.kind === 'repo') return 'published repo';
		if (props.item.kind === 'issue') return 'created issue in';
		if (props.item.kind === 'pull') return 'opened pull request in';
		return 'updated';
	};

	const preloadProps = () => {
		if (props.item.kind === 'issue' || props.item.kind === 'pull') {
			if (props.item.uri) {
				return issuePreloader(props.item.repoLabel, props.item.kind, props.item.uri);
			}
		}
		return {};
	};

	const preloadRepoProps = () => {
		const [owner, slug] = props.item.repoLabel.split('/');
		return preloadRepo(owner, slug);
	};

	return (
		<div class="relative">
			<Show when={props.index > 0}>
				<div class="absolute left-8 -top-4 w-px h-4 bg-gray-300 dark:bg-gray-600" />
			</Show>
			<div class="flex flex-col divide-y divide-gray-200 dark:divide-gray-700 border border-gray-200 dark:border-gray-700 rounded-sm">
				{/* Header row */}
				<div class="pl-6 py-2 bg-white dark:bg-gray-800 text-gray-600 dark:text-gray-300 flex items-center gap-2 text-sm min-w-0 overflow-hidden">
					<Show when={props.item.actorDid}>
						<Avatar did={props.item.actorDid!} size="size-5" />
					</Show>
					<A
						href={actorUrl()}
						class="font-bold no-underline hover:underline text-black dark:text-white truncate shrink-0 max-w-[8rem] sm:max-w-none"
					>
						{props.item.actorHandle || 'user'}
					</A>
					<span class="whitespace-nowrap shrink-0">{actionText()}</span>
					<A
						href={repoUrl()}
						class="no-underline hover:underline font-bold text-black dark:text-white truncate min-w-0"
						{...preloadRepoProps()}
					>
						{props.item.repoLabel}
					</A>
					<span class="text-gray-400 dark:text-gray-500 text-xs ml-auto pr-6 shrink-0 whitespace-nowrap">
						{formatRelativeTime(props.item.at)}
					</span>
				</div>

				{/* Content row */}
				<Show
					when={props.item.kind === 'repo'}
					fallback={
						<div class="py-4 px-6 flex flex-col gap-1 bg-white dark:bg-gray-800">
							<div class="font-medium text-black dark:text-white flex items-center">
								<Show
									when={props.item.kind === 'pull'}
									fallback={<CircleDot class="w-4 h-4 mr-1.5 shrink-0 text-green-600" />}
								>
									<GitPullRequest class="w-4 h-4 mr-1.5 shrink-0 text-purple-600" />
								</Show>
								<A
									href={props.item.href}
									class="no-underline hover:underline font-medium text-black dark:text-white text-base"
									{...preloadProps()}
								>
									{props.item.title}
								</A>
							</div>
							<Show when={props.item.body}>
								<div class="text-gray-600 dark:text-gray-300 text-sm line-clamp-2 mt-1">{props.item.body}</div>
							</Show>
						</div>
					}
				>
					<RepoCard
						owner={props.item.repoLabel.split('/')[0]}
						name={props.item.repoLabel.split('/')[1]}
						description={props.item.body}
						href={props.item.href}
						noBorder
					/>
				</Show>
			</div>
		</div>
	);
};

