<script lang="ts">
	import { onMount } from 'svelte';
	import type { ChartElement } from '../types';

	interface Props { element: ChartElement; slideId: string; }
	let { element, slideId }: Props = $props();

	let animationProgress = $state(1);
	let animationFrame: number | null = null;

	function animateChart() {
		const startTime = performance.now();
		const duration = element.animationDuration;

		function tick() {
			const elapsed = performance.now() - startTime;
			const progress = Math.min(elapsed / duration, 1);
			// Ease out cubic
			const eased = 1 - Math.pow(1 - progress, 3);
			animationProgress = eased;

			if (progress < 1) {
				animationFrame = requestAnimationFrame(tick);
			}
		}

		// Cancel any existing animation
		if (animationFrame) cancelAnimationFrame(animationFrame);

		// Start animation after a short delay
		setTimeout(() => {
			animationProgress = 0;
			animationFrame = requestAnimationFrame(tick);
		}, 200);
	}

	// Trigger animation on mount
	onMount(() => {
		animateChart();
		return () => {
			if (animationFrame) cancelAnimationFrame(animationFrame);
		};
	});

	// Also trigger when slideId changes
	$effect(() => {
		if (slideId) {
			animateChart();
		}
	});

	// Calculate max value for scaling
	const maxValue = $derived(Math.max(...element.data.map(d => d.value), 1));

	// Calculate line/area chart points
	const linePoints = $derived.by(() => {
		return element.data.map((d, i) => {
			const x = 10 + (i / Math.max(element.data.length - 1, 1)) * 80;
			const y = 90 - (d.value / maxValue) * 80 * animationProgress;
			return `${x},${y}`;
		}).join(' ');
	});

	// Get color for data point
	function getColor(index: number, customColor?: string): string {
		if (customColor) return customColor;
		return element.colors[index % element.colors.length];
	}

	// Calculate pie/donut segments
	const pieSegments = $derived.by(() => {
		const total = element.data.reduce((sum, d) => sum + d.value, 0);
		let currentAngle = -90; // Start from top

		return element.data.map((d, i) => {
			const percentage = d.value / total;
			const angle = percentage * 360 * animationProgress;
			const startAngle = currentAngle;
			currentAngle += angle;

			return {
				...d,
				startAngle,
				endAngle: currentAngle,
				percentage,
				color: getColor(i, d.color)
			};
		});
	});

	// SVG arc path for pie
	function describeArc(cx: number, cy: number, r: number, startAngle: number, endAngle: number): string {
		const start = polarToCartesian(cx, cy, r, endAngle);
		const end = polarToCartesian(cx, cy, r, startAngle);
		const largeArcFlag = endAngle - startAngle <= 180 ? 0 : 1;

		return [
			'M', cx, cy,
			'L', start.x, start.y,
			'A', r, r, 0, largeArcFlag, 0, end.x, end.y,
			'Z'
		].join(' ');
	}

	// SVG arc path for donut
	function describeDonutArc(cx: number, cy: number, outerR: number, innerR: number, startAngle: number, endAngle: number): string {
		const outerStart = polarToCartesian(cx, cy, outerR, endAngle);
		const outerEnd = polarToCartesian(cx, cy, outerR, startAngle);
		const innerStart = polarToCartesian(cx, cy, innerR, endAngle);
		const innerEnd = polarToCartesian(cx, cy, innerR, startAngle);
		const largeArcFlag = endAngle - startAngle <= 180 ? 0 : 1;

		return [
			'M', outerStart.x, outerStart.y,
			'A', outerR, outerR, 0, largeArcFlag, 0, outerEnd.x, outerEnd.y,
			'L', innerEnd.x, innerEnd.y,
			'A', innerR, innerR, 0, largeArcFlag, 1, innerStart.x, innerStart.y,
			'Z'
		].join(' ');
	}

	function polarToCartesian(cx: number, cy: number, r: number, angle: number) {
		const rad = (angle * Math.PI) / 180;
		return {
			x: cx + r * Math.cos(rad),
			y: cy + r * Math.sin(rad)
		};
	}
</script>

<div
	class="chart"
	style:background-color={element.backgroundColor}
	style:padding="{element.padding}px"
	style:border-radius="{element.borderRadius}px"
	style:color={element.textColor}
	style:font-size="{element.fontSize}px"
>
	{#if element.title}
		<div class="chart-title">{element.title}</div>
	{/if}

	<div class="chart-content">
		{#if element.chartType === 'bar'}
			<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" class="bar-chart">
				{#if element.showGrid}
					{#each [0, 25, 50, 75, 100] as y}
						<line x1="0" y1={y} x2="100" y2={y} stroke="currentColor" stroke-opacity="0.1" stroke-width="0.5" />
					{/each}
				{/if}
				{#each element.data as point, i}
					{@const barWidth = 80 / element.data.length}
					{@const barX = 10 + i * (barWidth + 5)}
					{@const barHeight = (point.value / maxValue) * 80 * animationProgress}
					<rect
						x={barX}
						y={90 - barHeight}
						width={barWidth}
						height={barHeight}
						fill={getColor(i, point.color)}
						rx="1"
					/>
					{#if element.showLabels}
						<text
							x={barX + barWidth / 2}
							y="98"
							text-anchor="middle"
							font-size="4"
							fill="currentColor"
						>{point.label}</text>
					{/if}
					{#if element.showValues}
						<text
							x={barX + barWidth / 2}
							y={88 - barHeight}
							text-anchor="middle"
							font-size="3.5"
							fill="currentColor"
						>{Math.round(point.value * animationProgress)}</text>
					{/if}
				{/each}
			</svg>
		{:else if element.chartType === 'line' || element.chartType === 'area'}
			<svg viewBox="0 0 100 100" preserveAspectRatio="xMidYMid meet" class="line-chart">
				{#if element.showGrid}
					{#each [0, 25, 50, 75, 100] as y}
						<line x1="0" y1={y} x2="100" y2={y} stroke="currentColor" stroke-opacity="0.1" stroke-width="0.5" />
					{/each}
					{#each element.data as _, i}
						{@const x = 10 + (i / (element.data.length - 1)) * 80}
						<line x1={x} y1="10" x2={x} y2="90" stroke="currentColor" stroke-opacity="0.1" stroke-width="0.5" />
					{/each}
				{/if}

				{#if element.chartType === 'area'}
					<polygon
						points="{linePoints} {10 + 80},90 10,90"
						fill={element.colors[0]}
						fill-opacity="0.3"
					/>
				{/if}

				<polyline
					points={linePoints}
					fill="none"
					stroke={element.colors[0]}
					stroke-width="2"
					stroke-linecap="round"
					stroke-linejoin="round"
				/>

				{#each element.data as point, i}
					{@const x = 10 + (i / Math.max(element.data.length - 1, 1)) * 80}
					{@const y = 90 - (point.value / maxValue) * 80 * animationProgress}
					<circle cx={x} cy={y} r="2" fill={getColor(i, point.color) || element.colors[0]} />
					{#if element.showLabels}
						<text x={x} y="98" text-anchor="middle" font-size="4" fill="currentColor">{point.label}</text>
					{/if}
					{#if element.showValues}
						<text x={x} y={y - 4} text-anchor="middle" font-size="3.5" fill="currentColor">{Math.round(point.value * animationProgress)}</text>
					{/if}
				{/each}
			</svg>
		{:else if element.chartType === 'pie'}
			<svg viewBox="0 0 100 100" class="pie-chart">
				{#each pieSegments as segment, i}
					{#if segment.endAngle - segment.startAngle > 0.1}
						{@const midAngle = (segment.startAngle + segment.endAngle) / 2}
						{@const valuePos = polarToCartesian(50, 50, 28, midAngle)}
						{@const labelPos = polarToCartesian(50, 50, 48, midAngle)}
						{@const textAnchor = midAngle > -90 && midAngle < 90 ? 'start' : 'end'}
						<path
							d={describeArc(50, 50, 40, segment.startAngle, segment.endAngle)}
							fill={segment.color}
						/>
						{#if element.showValues}
							<text
								x={valuePos.x}
								y={valuePos.y}
								text-anchor="middle"
								dominant-baseline="middle"
								font-size="4"
								fill="white"
								font-weight="600"
							>{Math.round(segment.percentage * 100)}%</text>
						{/if}
						{#if element.showLabels}
							<text
								x={labelPos.x}
								y={labelPos.y}
								text-anchor={textAnchor}
								dominant-baseline="middle"
								font-size="3.5"
								fill="currentColor"
							>{element.data[i].label}</text>
						{/if}
					{/if}
				{/each}
				{#if element.showLegend}
					{#each element.data as point, i}
						<rect x="85" y={10 + i * 8} width="4" height="4" fill={getColor(i, point.color)} />
						<text x="91" y={14 + i * 8} font-size="4" fill="currentColor">{point.label}</text>
					{/each}
				{/if}
			</svg>
		{:else if element.chartType === 'donut'}
			<svg viewBox="0 0 100 100" class="donut-chart">
				{#each pieSegments as segment, i}
					{#if segment.endAngle - segment.startAngle > 0.1}
						{@const midAngle = (segment.startAngle + segment.endAngle) / 2}
						{@const valuePos = polarToCartesian(50, 50, 32.5, midAngle)}
						{@const labelPos = polarToCartesian(50, 50, 48, midAngle)}
						{@const textAnchor = midAngle > -90 && midAngle < 90 ? 'start' : 'end'}
						<path
							d={describeDonutArc(50, 50, 40, 25, segment.startAngle, segment.endAngle)}
							fill={segment.color}
						/>
						{#if element.showValues}
							<text
								x={valuePos.x}
								y={valuePos.y}
								text-anchor="middle"
								dominant-baseline="middle"
								font-size="3.5"
								fill="white"
								font-weight="600"
							>{Math.round(segment.percentage * 100)}%</text>
						{/if}
						{#if element.showLabels}
							<text
								x={labelPos.x}
								y={labelPos.y}
								text-anchor={textAnchor}
								dominant-baseline="middle"
								font-size="3.5"
								fill="currentColor"
							>{element.data[i].label}</text>
						{/if}
					{/if}
				{/each}
				{#if element.showLegend}
					{#each element.data as point, i}
						<rect x="85" y={10 + i * 8} width="4" height="4" fill={getColor(i, point.color)} />
						<text x="91" y={14 + i * 8} font-size="4" fill="currentColor">{point.label}</text>
					{/each}
				{/if}
			</svg>
		{/if}
	</div>
</div>

<style>
	.chart {
		width: 100%;
		height: 100%;
		display: flex;
		flex-direction: column;
		box-sizing: border-box;
		overflow: hidden;
	}

	.chart-title {
		font-weight: 600;
		text-align: center;
		margin-bottom: 8px;
	}

	.chart-content {
		flex: 1;
		min-height: 0;
	}

	.chart-content svg {
		width: 100%;
		height: 100%;
	}

	.bar-chart, .line-chart {
		overflow: visible;
	}
</style>
