<script lang="ts">
	import type { BookMetadata } from "@src/types";
	import type {
		PieChartColor,
		PieGrouping,
	} from "@ui/code-blocks/ReadingStatsCodeBlock";
	import { chart } from "@ui/directives/chart";
	import { createPropertyStore } from "@ui/stores/metadata.svelte";
	import { Color, type ColorName } from "@utils/color";
	import type { ChartConfiguration } from "chart.js";

	type Props = {
		property: keyof BookMetadata;
		groups?: PieGrouping[];
		unit?: string;
		unitPlural?: string;
		responsive?: boolean;
		color?: PieChartColor;
	};

	const { property, groups, unit, unitPlural, responsive, color }: Props =
		$props();

	const store = createPropertyStore(property);

	function makeLabel(value: any) {
		if (typeof value === "number") {
			let label = value.toString();

			if (unitPlural && value !== 1) {
				label += ` ${unitPlural}`;
			} else if (unit) {
				label += ` ${unit}`;
				if (value !== 1) {
					label += "s";
				}
			}

			return label;
		} else {
			return value;
		}
	}

	const config = $derived.by(() => {
		const map = new Map<any, number>();

		if (groups) {
			for (const group of groups) {
				map.set(group.label, 0);
			}
		}

		for (const { value } of store.propertyData) {
			if (groups) {
				for (const group of groups) {
					if (group.min && value < group.min) {
						continue;
					}
					if (group.max && value > group.max) {
						continue;
					}

					const count = map.get(group.label) ?? 0;
					map.set(group.label, count + 1);
				}
			} else if (Array.isArray(value)) {
				for (const v of value) {
					const count = map.get(v) ?? 0;
					map.set(v, count + 1);
				}
			} else {
				const count = map.get(value) ?? 0;
				map.set(value, count + 1);
			}
		}

		const labels = Array.from(map.keys()).map((p) => makeLabel(p));
		const data = Array.from(map.values());

		let backgroundColor: string[] | string | undefined = Color.scale(
			data.length,
		).map((c) => c.hex);
		if (color) {
			if (color === "rainbow") {
				backgroundColor = Color.scale(data.length).map((c) => c.hex);
			} else if (typeof color === "string") {
				backgroundColor = Color.fromName(color).hex;
			} else if (Array.isArray(color)) {
				if (color.length < data.length) {
					throw new Error(
						"Color array must be at least as long as the data array",
					);
				}

				if (color.every((c) => typeof c === "string")) {
					backgroundColor = color;
				} else {
					const map = color.reduce(
						(acc, c) => {
							acc[c.label] = c.color;
							return acc;
						},
						{} as Record<string, ColorName>,
					);

					backgroundColor = labels.map(
						(label) => Color.fromName(map[label]).hex,
					);
				}
			}
		}

		return {
			type: "pie",
			data: { labels, datasets: [{ data, backgroundColor }] },
			options: { responsive },
		} as ChartConfiguration;
	});
</script>

<canvas use:chart={config}></canvas>
