Chapters read distribution chart component.

export const ChaptersReadDistributionChart: FC<ChaptersReadDistributionChartProps> =
React.memo(function ChaptersReadDistributionChartMemo({
// eslint-disable-next-line react/prop-types
matchResults,
// eslint-disable-next-line react/prop-types
className,
}) {
const { bins, stats } = useMemo(
() => buildHistogram(matchResults),
[matchResults],
);

const hasData = bins.length > 0;

return (
<section
aria-label="Chapters read distribution"
className={cn(
"rounded-2xl border border-slate-200 bg-white/90 p-6 shadow-sm backdrop-blur-md dark:border-slate-800 dark:bg-slate-900/90",
className,
)}
>
<header className="mb-4 flex flex-col gap-3">
<div className="flex items-center gap-2">
<span className="bg-linear-to-r inline-flex h-9 min-h-9 w-9 min-w-9 items-center justify-center rounded-full from-blue-500/20 via-purple-500/20 to-fuchsia-500/20 text-blue-500 dark:text-blue-300">
<BarChart2 className="h-4 w-4" aria-hidden="true" />
</span>
<div>
<h2 className="text-foreground text-lg font-semibold">
Reading Progress Distribution
</h2>
<p className="text-muted-foreground mt-1 text-sm">
Chapters read per manga based on your matched Kenmei entries.
</p>
</div>
</div>

{hasData && (
<div className="text-muted-foreground flex flex-wrap items-center gap-2 text-sm">
<Badge
variant="secondary"
className="bg-emerald-500/15 text-emerald-600 dark:text-emerald-300"
>
Total: {stats.totalChapters.toLocaleString()} chapters
</Badge>
<Badge
variant="secondary"
className="bg-blue-500/15 text-blue-600 dark:text-blue-300"
>
Average: {stats.averageChapters.toFixed(1)}
</Badge>
<Badge
variant="secondary"
className="bg-purple-500/15 text-purple-600 dark:text-purple-300"
>
Median: {stats.medianChapters.toFixed(1)}
</Badge>
{stats.modeRange && (
<Badge
variant="secondary"
className="bg-amber-500/15 text-amber-600 dark:text-amber-300"
>
Mode: {stats.modeRange}
</Badge>
)}
</div>
)}
</header>

{hasData ? (
<figure className="h-[300px] w-full">
<ResponsiveContainer width="100%" height="100%">
<BarChart data={bins} barCategoryGap={18}>
<CartesianGrid strokeDasharray="3 3" stroke="var(--border)" />
<XAxis
dataKey="range"
tickLine={false}
axisLine={false}
tick={{ fontSize: 12 }}
label={{
value: "Chapters Read",
position: "insideBottom",
offset: -6,
className: "fill-current text-xs text-muted-foreground",
}}
/>
<YAxis
allowDecimals={false}
tickLine={false}
axisLine={false}
tick={{ fontSize: 12 }}
label={{
value: "Number of Manga",
angle: -90,
position: "insideLeft",
offset: 10,
className: "fill-current text-xs text-muted-foreground",
}}
/>
<Tooltip
contentStyle={{
backgroundColor: "hsl(var(--muted))",
borderRadius: "calc(var(--radius) - 4px)",
padding: "0.5rem 0.75rem",
border: "none",
}}
labelStyle={{ color: "hsl(var(--muted-foreground))" }}
formatter={(value: number) =>
`${Number(value).toLocaleString()} manga`
}
/>
<Bar
dataKey="count"
fill="url(#chaptersGradient)"
radius={[8, 8, 0, 0]}
animationDuration={800}
/>
<defs>
<linearGradient
id="chaptersGradient"
x1="0"
x2="0"
y1="0"
y2="1"
>
<stop offset="0%" stopColor="#3b82f6" stopOpacity={0.95} />
<stop
offset="100%"
stopColor="#a855f7"
stopOpacity={0.75}
/>
</linearGradient>
</defs>
</BarChart>
</ResponsiveContainer>
</figure>
) : (
<div className="text-muted-foreground flex flex-col items-center justify-center rounded-xl border border-dashed border-slate-200 bg-slate-50/60 p-8 text-center dark:border-slate-800 dark:bg-slate-900/60">
<AlertCircle className="mb-3 h-6 w-6" aria-hidden="true" />
<p className="font-medium">No reading progress data available</p>
<p className="mt-1 text-sm">
Chapters read are calculated from Kenmei data once matches are
confirmed.
</p>
</div>
)}
</section>
);
});