<script setup lang="ts">
import { Icon } from '@bagelink/vue'
import { computed, ref, onMounted, onUnmounted } from 'vue'

interface PieData {
	label: string
	value: number
	color?: string
}

interface Props {
	data: PieData[]
	title?: string
	icon?: string
	color?: string
	colors?: string[]
	size?: number
	showLegend?: boolean
	donut?: boolean
	thickness?: number
	centerLabel?: string
	animated?: boolean
	animationDuration?: number
	animationDelay?: number
	animationStartDelay?: number
	centerValue?: number
	showCenterTotal?: boolean
	percentageChange?: number
	showLabelsOnChart?: boolean
	showConnectorLines?: boolean
	labelColor?: string
}

const props = withDefaults(defineProps<Props>(), {
	title: 'Pie Chart',
	icon: 'bx-pie-chart-alt',
	color: '#3B82F6',
	size: 200,
	showLegend: true,
	donut: false,
	thickness: 0.6,
	animated: true,
	animationDuration: 1500,
	animationDelay: 200,
	animationStartDelay: 0,
	centerLabel: 'Total',
	showCenterTotal: true,
	percentageChange: 0,
	showLabelsOnChart: false,
	showConnectorLines: false,
	labelColor: '#333'
})

// Generate colors with different opacity based on the main color OR use custom colors
const colors = computed(() => {
	// If custom colors array is provided, use it
	if (props.colors && props.colors.length > 0) {
		return props.colors
	}

	// Otherwise, use the existing logic with opacity variations
	const baseColor = props.color
	const opacities = [1, 0.8, 0.6, 0.4, 0.85, 0.7, 0.5, 0.3, 0.9, 0.75]

	return opacities.map((opacity) => {
		// Convert hex to rgba with opacity
		const hex = baseColor.replace('#', '')
		const r = Number.parseInt(hex.substr(0, 2), 16)
		const g = Number.parseInt(hex.substr(2, 2), 16)
		const b = Number.parseInt(hex.substr(4, 2), 16)

		return `rgba(${r}, ${g}, ${b}, ${opacity})`
	})
})

// Animation state
const animatedProgress = ref(0)
const isAnimating = ref(false)
const chartRef = ref<HTMLElement>()
const isInView = ref(false)

onMounted(() => {
	if (props.animated) {
		setupIntersectionObserver()
	} else {
		animatedProgress.value = 1
	}
})

let observer: IntersectionObserver | null = null

onUnmounted(() => {
	if (observer) {
		observer.disconnect()
	}
})

function setupIntersectionObserver() {
	if (typeof window === 'undefined') { return }

	observer = new IntersectionObserver(
		(entries) => {
			entries.forEach((entry) => {
				if (entry.isIntersecting && !isInView.value) {
					isInView.value = true
					// Add start delay + small delay to ensure the component is fully rendered
					setTimeout(() => {
						startAnimation()
					}, 100 + props.animationStartDelay)
				}
			})
		},
		{
			threshold: 0.3, // Start animation when 30% of the component is visible
			rootMargin: '50px'
		}
	)

	// Use nextTick to ensure chartRef is available
	if (chartRef.value) {
		observer.observe(chartRef.value)
	} else {
		// Retry after a short delay if ref is not ready
		setTimeout(() => {
			if (chartRef.value && observer) {
				observer.observe(chartRef.value)
			}
		}, 100)
	}
}

function startAnimation() {
	const delayType = props.animationDelay > 0 ? 'staggered with delay' : 'quick stagger'
	console.log(`Starting animation for "${props.title}" - ${delayType} mode (duration: ${props.animationDuration}ms, start delay: ${props.animationStartDelay}ms)`)
	isAnimating.value = true
	animatedProgress.value = 0

	const startTime = Date.now()

	const animate = () => {
		const elapsed = Date.now() - startTime
		const progress = Math.min(elapsed / props.animationDuration, 1)

		// Easing function for smooth animation
		animatedProgress.value = easeOutCubic(progress)

		if (progress < 1) {
			requestAnimationFrame(animate)
		} else {
			isAnimating.value = false
			console.log('Animation completed')
		}
	}

	requestAnimationFrame(animate)
}

function easeOutCubic(t: number): number {
	return 1 - (1 - t) ** 3
}

// Expose animation control methods
function restartAnimation() {
	if (props.animated) {
		startAnimation()
	}
}

defineExpose({
	restartAnimation
})

// Calculate SVG size based on connector lines
const svgSize = computed(() => {
	if (props.showConnectorLines) {
		return {
			width: props.size + 200, // Increased even more
			height: props.size + 100 // Increased even more
		}
	}
	return {
		width: props.size,
		height: props.size
	}
})

// Calculate center offset for connector lines
const centerOffset = computed(() => {
	if (props.showConnectorLines) {
		return {
			x: svgSize.value.width / 2 - 10, // Less offset
			y: svgSize.value.height / 2
		}
	}
	return {
		x: props.size / 2,
		y: props.size / 2
	}
})

const totalValue = computed(() => props.data.reduce((sum, item) => sum + item.value, 0)
)

// Calculate label positions for segments
function getLabelPosition(segment: any) {
	const midAngle = (segment.startAngle + segment.endAngle) / 2
	const midAngleRad = (midAngle * Math.PI) / 180
	const radius = props.size / 2 - 10
	const labelRadius = props.donut ? radius * 0.8 : radius * 0.7

	return {
		x: Math.cos(midAngleRad) * labelRadius,
		y: Math.sin(midAngleRad) * labelRadius
	}
}

// Calculate connector line positions
function getConnectorLine(segment: any) {
	const midAngle = (segment.startAngle + segment.endAngle) / 2
	const midAngleRad = (midAngle * Math.PI) / 180
	const radius = props.size / 2 - 10
	const innerRadius = props.donut ? radius * props.thickness : radius * 0.5
	const outerRadius = radius + 15 // Reduced from 20 to 15

	const innerX = Math.cos(midAngleRad) * innerRadius
	const innerY = Math.sin(midAngleRad) * innerRadius
	const outerX = Math.cos(midAngleRad) * outerRadius
	const outerY = Math.sin(midAngleRad) * outerRadius

	// Extended line for label - reduced extension
	const labelX = outerX + (outerX > 0 ? 8 : -8) // Reduced from 10 to 8
	const labelY = outerY

	return {
		innerX,
		innerY,
		outerX,
		outerY,
		labelX,
		labelY,
		textAnchor: outerX > 0 ? 'start' : 'end'
	}
}

const centerDisplayValue = computed(() => {
	if (props.centerValue !== undefined) {
		return props.centerValue
	}
	return props.showCenterTotal ? totalValue.value : 0
})

const pieSegments = computed(() => {
	let cumulativeAngle = 0
	return props.data.map((item, index) => {
		const percentage = item.value / totalValue.value
		const angle = percentage * 360

		const startAngle = cumulativeAngle
		const endAngle = cumulativeAngle + angle
		cumulativeAngle += angle

		// Calculate if this segment should be visible based on animation progress
		// Add a small delay even for the first segment to avoid immediate appearance
		const baseDelay = 100 // 100ms delay for the first segment
		const segmentDelay = props.animationDelay > 0
			? baseDelay + (index * props.animationDelay)
			: baseDelay + (index * 50) // Small stagger even when animationDelay is 0
		const totalElapsedTime = animatedProgress.value * props.animationDuration
		const isVisible = !props.animated || totalElapsedTime >= segmentDelay

		// Debug log for animation
		if (props.animated && index === 0) {
			console.log(`Animation progress: ${(animatedProgress.value * 100).toFixed(1)}%, elapsed: ${totalElapsedTime.toFixed(0)}ms`)
		}

		if (!isVisible) {
			if (index < 3) {
				console.log(`Segment ${index} waiting - needs ${segmentDelay}ms, current: ${totalElapsedTime.toFixed(0)}ms`)
			}
			return {
				...item,
				percentage,
				angle: 0,
				startAngle,
				endAngle: startAngle,
				path: '',
				color: item.color || colors.value[index % colors.value.length],
				visible: false
			}
		} if (index < 3) {
			console.log(`Segment ${index} visible! - delay: ${segmentDelay}ms, elapsed: ${totalElapsedTime.toFixed(0)}ms`)
		}

		const startAngleRad = (startAngle * Math.PI) / 180
		const endAngleRad = (endAngle * Math.PI) / 180

		const radius = props.size / 2 - 10
		const innerRadius = props.donut ? radius * props.thickness : 0

		const segmentAngle = endAngle - startAngle
		const largeArcFlag = segmentAngle > 180 ? 1 : 0

		const pathData = props.donut
			? createDonutPath(startAngleRad, endAngleRad, radius, innerRadius, largeArcFlag)
			: createPiePath(startAngleRad, endAngleRad, radius, largeArcFlag)

		return {
			...item,
			percentage,
			angle: segmentAngle,
			startAngle,
			endAngle,
			path: pathData,
			color: item.color || colors.value[index % colors.value.length],
			visible: true
		}
	})
})

function createPiePath(startAngle: number, endAngle: number, radius: number, largeArcFlag: number): string {
	const x1 = Math.cos(startAngle) * radius
	const y1 = Math.sin(startAngle) * radius
	const x2 = Math.cos(endAngle) * radius
	const y2 = Math.sin(endAngle) * radius

	return `M 0 0 L ${x1} ${y1} A ${radius} ${radius} 0 ${largeArcFlag} 1 ${x2} ${y2} Z`
}

function createDonutPath(startAngle: number, endAngle: number, outerRadius: number, innerRadius: number, largeArcFlag: number): string {
	const x1Outer = Math.cos(startAngle) * outerRadius
	const y1Outer = Math.sin(startAngle) * outerRadius
	const x2Outer = Math.cos(endAngle) * outerRadius
	const y2Outer = Math.sin(endAngle) * outerRadius

	const x1Inner = Math.cos(startAngle) * innerRadius
	const y1Inner = Math.sin(startAngle) * innerRadius
	const x2Inner = Math.cos(endAngle) * innerRadius
	const y2Inner = Math.sin(endAngle) * innerRadius

	return `M ${x1Outer} ${y1Outer} A ${outerRadius} ${outerRadius} 0 ${largeArcFlag} 1 ${x2Outer} ${y2Outer} L ${x2Inner} ${y2Inner} A ${innerRadius} ${innerRadius} 0 ${largeArcFlag} 0 ${x1Inner} ${y1Inner} Z`
}

function formatValue(value: number): string {
	return value.toLocaleString()
}

function formatPercentage(percentage: number): string {
	return `${(percentage * 100).toFixed(1)}%`
}

function formatTooltip(segment: any): string {
	return `<div class="pieTooltip">
	<div class="round w-10px h-10px w-100p inline-block" style="background-color: ${segment.color};"></div>
	<p class="inline-block txt12">${segment.label}</p>
	<div class="gap-025 flex">
	<p class="bold txt18">${formatValue(segment.value)}</p>
	<p>|</p>
	<p class="bold txt18">${formatPercentage(segment.percentage)}</p></div>`
}
</script>

<template>
	<div ref="chartRef" class="h-100p flex column flex-stretch">
		<div class="flex space-between  pb-1">
			<div class="flex align-center gap-05">
				<Icon :name="icon" size="1.2" :color="color" class="line-height-0" />
				<p class="white-space light m_txt14">
					{{ title }}
				</p>
			</div>
			<div v-if="percentageChange !== 0" class="flex align-center gap-025">
				<Icon class="line-height-1" :name="percentageChange > 0 ? 'trending_up' : 'trending_down'" size="1" :class="percentageChange > 0 ? 'color-success' : 'color-danger'" />
				<span class="txt12 bold" :class="percentageChange > 0 ? 'color-success' : 'color-danger'">
					{{ Math.abs(percentageChange) }}%
				</span>
			</div>
		</div>
		<div class="chart-container flex space-between gap-1 flex-wrap flex-grow" :class="{ 'with-legend': showLegend, 'with-connectors': showConnectorLines }">
			<svg :width="svgSize.width" :height="svgSize.height" class="chart-svg mx-auto flex-shrink-0" :style="showConnectorLines ? 'overflow: visible;' : ''">
				<g :transform="`translate(${centerOffset.x}, ${centerOffset.y})`">
					<path
						v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="index" v-tooltip="{ content: formatTooltip(segment), html: true }" :d="segment.path" :fill="segment.color"
						class="pie-segment" stroke="white" stroke-width="2"
					/>

					<!-- Center text for donut chart -->
					<g v-if="donut && (showCenterTotal || centerValue !== undefined)" class="center-text">
						<text x="0" y="-8" text-anchor="middle" dominant-baseline="middle" class="center-label txt12 opacity-7">
							{{ centerLabel }}
						</text>
						<text x="0" y="12" text-anchor="middle" dominant-baseline="middle" class="center-value txt20 bold">
							{{ formatValue(centerDisplayValue) }}
						</text>
					</g>

					<!-- Connector lines -->
					<g v-if="showConnectorLines" class="connector-lines">
						<g v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="`line-${index}`">
							<polyline
								:points="`${getConnectorLine(segment).innerX},${getConnectorLine(segment).innerY} ${getConnectorLine(segment).outerX},${getConnectorLine(segment).outerY} ${getConnectorLine(segment).labelX},${getConnectorLine(segment).labelY}`"
								stroke="#333" stroke-width="1.5" fill="none"
							/>
						</g>
					</g>

					<!-- Labels on chart -->
					<g v-if="showLabelsOnChart" class="chart-labels">
						<!-- Labels without connector lines -->
						<g v-if="!showConnectorLines">
							<text
								v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="`label-${index}`" :x="getLabelPosition(segment).x" :y="getLabelPosition(segment).y - 5"
								text-anchor="middle" dominant-baseline="middle" class="chart-label txt12 pointer-events-none" :fill="labelColor"
							>
								{{ segment.label }}
							</text>
							<text
								v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="`value-${index}`" :x="getLabelPosition(segment).x" :y="getLabelPosition(segment).y + 12"
								text-anchor="middle" dominant-baseline="middle" class="chart-value txt16 mt-1 line-height-2 bold pointer-events-none" :fill="labelColor"
							>
								{{ formatValue(segment.value) }}
							</text>
						</g>

						<!-- Labels with connector lines -->
						<template v-if="showConnectorLines">
							<text
								v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="`label-line-${index}`" :x="getConnectorLine(segment).labelX"
								:y="getConnectorLine(segment).labelY - 8" :text-anchor="getConnectorLine(segment).textAnchor" dominant-baseline="middle" class="chart-label txt12 bold" :fill="labelColor"
							>
								{{ segment.label }}
							</text>

							<!-- Value labels with connector lines -->
							<text
								v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="`value-line-${index}`" :x="getConnectorLine(segment).labelX"
								:y="getConnectorLine(segment).labelY + 2" :text-anchor="getConnectorLine(segment).textAnchor" dominant-baseline="middle" class="chart-value txt11" fill="#666"
							>
								{{ formatValue(segment.value) }}
							</text>

							<!-- Percentage labels with connector lines -->
							<text
								v-for="(segment, index) in pieSegments.filter(s => s.visible)" :key="`percentage-${index}`" :x="getConnectorLine(segment).labelX"
								:y="getConnectorLine(segment).labelY + 15" :text-anchor="getConnectorLine(segment).textAnchor" dominant-baseline="middle" class="chart-percentage txt10 pointer-events-none"
								fill="#999"
							>
								({{ formatPercentage(segment.percentage) }})
							</text>
						</template>
					</g>
				</g>
			</svg>

			<div v-if="showLegend" class="legend mx-auto display-flex column gap-05 min-w-100px">
				<div v-for="(segment, index) in pieSegments" :key="index" class="gap-1 flex align-items-center txt14 justify-content-start">
					<div class="legend-color flex-shrink-0 radius-05" :style="{ backgroundColor: segment.color }" />
					<span v-if="segment.label" class="flex-shrink-1 flex-grow-1">{{ segment.label }}</span>
					<span class="bold">{{ formatValue(segment.value) }}</span>
					<span class="opacity-6 txt12">({{ formatPercentage(segment.percentage) }})</span>
				</div>
			</div>
		</div>
	</div>
</template>

<style scoped>
.pie-segment {
	transition: opacity 0.3s ease;
}

[dir="rtl"] .chart-container.with-legend {
	flex-direction: row-reverse;
}

.pie-segment {
	cursor: pointer;
	transition: opacity 0.2s ease;
	animation: fadeIn 0.3s ease-in-out;
}

@keyframes fadeIn {
	from {
		opacity: 0;
	}

	to {
		opacity: 1;
	}
}

.pie-segment:hover {
	opacity: 0.8;
}

/* RTL support for legend */
[dir="rtl"] .legend-item {
	flex-direction: row-reverse;
}

.legend-color {
	width: 12px;
	height: 12px;
}

.connector-lines polyline {
	opacity: 0.8;
}

.chart-container.with-connectors {
	overflow: visible;
	padding: 10px;
}

.chart-container.with-connectors .chart-svg {
	overflow: visible;
}

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

.chart-container {
	min-height: 0;
	align-items: center;
}

.chart-container.flex-grow {
	flex: 1;
}
</style>

<style>
.v-popper--theme-tooltip .v-popper__inner:has(.pieTooltip) {
	background-color: var(--bgl-black) !important;
	color: var(--bgl-white) !important;
	border-radius: 0.5rem !important;
	padding: 0.25rem 0.5rem !important;
}
</style>
