import { Info } from "lucide-react";
import { BrandLookupMentionTrendCard } from "@/client/features/ai-search/components/BrandLookupMentionTrendCard";
import { BrandLookupShareOfVoice } from "@/client/features/ai-search/components/BrandLookupShareOfVoice";
import { CitationTabsCard } from "@/client/features/ai-search/components/BrandLookupCitationsCard";
import {
formatCount,
formatPlatformLabel,
PLATFORM_DOT_CLASS,
} from "@/client/features/ai-search/platformLabels";
import type { BrandLookupResult } from "@/types/schemas/ai-search";
type Props = {
result: BrandLookupResult;
projectId: string;
};
type PlatformRow = BrandLookupResult["perPlatform"][number];
type MetricKey = "mentions" | "aiSearchVolume";
export function BrandLookupResults({ result, projectId }: Props) {
if (!result.hasData) {
const erroredPlatforms = result.perPlatform.filter(
(p) => p.status === "error",
);
const allPlatformsErrored =
erroredPlatforms.length === result.perPlatform.length &&
result.perPlatform.length > 0;
if (allPlatformsErrored) {
return (
AI mention data is temporarily unavailable for{" "}
{result.resolvedTarget}. Please try again shortly.
);
}
return (
No AI mentions found for {result.resolvedTarget}.
{erroredPlatforms.length > 0 ? (
Note:{" "}
{erroredPlatforms
.map((p) => formatPlatformLabel(p.platform))
.join(" and ")}{" "}
{erroredPlatforms.length === 1 ? "was" : "were"} unavailable — some
mentions may be missing.
) : null}
);
}
const hasTrendData = result.monthlyVolume.length > 0;
const sov = result.shareOfVoice;
return (
{/* One shared grid so the cards align by construction: stats left, trend
right, Share of Voice flowing into the next free half-width cell —
whichever of trend/SoV is absent, the rest stay column-aligned. A
lone stats card keeps full width instead of half a grid. */}
{hasTrendData ? : null}
{sov ? : null}
);
}
function BrandHeader({ result }: { result: BrandLookupResult }) {
return (
{result.resolvedTarget}
{result.detectedTargetType}
Updated {formatRelative(result.fetchedAt)}
);
}
function StatsCard({ result }: { result: BrandLookupResult }) {
return (
);
}
function StatBlock({
label,
tooltip,
value,
perPlatform,
metric,
}: {
label: string;
tooltip: string;
value: number | null;
perPlatform: PlatformRow[];
metric: MetricKey;
}) {
return (
{label}
{formatCount(value)}
{perPlatform.map((row) => (
))}
);
}
function PlatformStatRow({
row,
metric,
}: {
row: PlatformRow;
metric: MetricKey;
}) {
const value = row.status === "error" ? null : row[metric];
return (
{formatPlatformLabel(row.platform)}
{row.platform === "chat_gpt" ? (
) : null}
{row.status === "error" ? (
unavailable
) : null}
{formatCount(value)}
);
}
function MentionTrendCard({ result }: { result: BrandLookupResult }) {
return (
Mention trend (last 12 months)
);
}
function formatRelative(iso: string): string {
const date = new Date(iso);
if (Number.isNaN(date.getTime())) return "just now";
const diffMs = Date.now() - date.getTime();
const diffMin = Math.floor(diffMs / 60_000);
if (diffMin < 1) return "just now";
if (diffMin < 60) return `${diffMin}m ago`;
const diffHr = Math.floor(diffMin / 60);
if (diffHr < 24) return `${diffHr}h ago`;
const diffDay = Math.floor(diffHr / 24);
return `${diffDay}d ago`;
}