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

interface DataPoint {
	date: string
	value: number
	label?: string
}

interface Props {
	data: DataPoint[]
	title?: string
	icon?: string
	color?: string
	height?: number
	showPoints?: boolean
	currency?: boolean
	animated?: boolean
	animationDuration?: number
	animationStartDelay?: number
	percentageChange?: number
}

const props = withDefaults(defineProps<Props>(), {
	title: 'Line Chart',
	icon: 'trending_up',
	color: 'var(--bgl-primary)',
	height: 200,
	showPoints: true,
	currency: false,
	animated: true,
	animationDuration: 1500,
	animationStartDelay: 0,
	percentageChange: 0
})

const svgRef = ref<SVGElement>()
const chartRef = ref<HTMLElement>()
const width = ref(600)
const height = ref(props.height)

// Animation state
const animatedProgress = ref(0)
const isAnimating = ref(false)
const isInView = ref(false)

let observer: IntersectionObserver | null = null

const padding = { top: 20, inline_end: 30, bottom: 25, inline_start: 60 }
const chartWidth = computed(() => width.value - padding.inline_start - padding.inline_end)
const chartHeight = computed(() => height.value - padding.top - padding.bottom)

// RTL-aware padding calculations
const paddingLeft = computed(() => {
	const isRTL = document.documentElement.dir === 'rtl'
		|| document.documentElement.getAttribute('lang') === 'he'
	return isRTL ? padding.inline_end : padding.inline_start
})

// RTL-aware label positioning
const labelXPosition = computed(() => {
	const isRTL = document.documentElement.dir === 'rtl'
		|| document.documentElement.getAttribute('lang') === 'he'
	return isRTL ? paddingLeft.value + chartWidth.value + 10 : paddingLeft.value - 10
})

const labelTextAnchor = computed(() => {
	const isRTL = document.documentElement.dir === 'rtl'
		|| document.documentElement.getAttribute('lang') === 'he'
	return isRTL ? 'start' : 'end'
})

const maxValue = computed(() => Math.max(...props.data.map(d => d.value), 0))
const minValue = computed(() => Math.min(...props.data.map(d => d.value), 0))

const xScale = computed(() => {
	const isRTL = document.documentElement.dir === 'rtl'
		|| document.documentElement.getAttribute('lang') === 'he'
	const domain = props.data.length - 1

	return (index: number) => {
		const position = (index / domain) * chartWidth.value
		// In RTL, reverse the x position so the chart flows from right to left
		return isRTL ? chartWidth.value - position : position
	}
})

const yScale = computed(() => {
	const range = maxValue.value - minValue.value || 1
	return (value: number) => chartHeight.value - ((value - minValue.value) / range) * chartHeight.value
})

const pathData = computed(() => {
	if (props.data.length === 0) { return '' }

	// Calculate how many points to show based on animation progress
	const totalPoints = props.data.length
	const visiblePoints = props.animated
		? Math.ceil(totalPoints * animatedProgress.value)
		: totalPoints

	const dataToShow = props.data.slice(0, Math.max(1, visiblePoints))

	const points = dataToShow.map((d, i) => `${i === 0 ? 'M' : 'L'} ${paddingLeft.value + xScale.value(i)} ${padding.top + yScale.value(d.value)}`
	).join(' ')

	return points
})

const visiblePoints = computed(() => {
	if (!props.animated) { return props.data }

	const totalPoints = props.data.length
	const pointsToShow = Math.ceil(totalPoints * animatedProgress.value)
	return props.data.slice(0, Math.max(1, pointsToShow))
})

const gridLines = computed(() => {
	const lines = []
	const step = chartHeight.value / 4
	for (let i = 0; i <= 4; i++) {
		const y = i * step
		const value = maxValue.value - (i / 4) * (maxValue.value - minValue.value)
		lines.push({ y, value })
	}
	return lines
})

function formatValue(value: number): string {
	if (props.currency) {
		return new Intl.NumberFormat('he-IL', {
			style: 'currency',
			currency: 'ILS',
			minimumFractionDigits: 0
		}).format(value)
	}
	return value.toLocaleString()
}

function formatDate(dateStr: string): string {
	const date = new Date(dateStr)
	return date.toLocaleDateString('he-IL', { month: 'short', day: 'numeric' })
}

function formatTooltip(point: any): string {
	const tooltipLines = [
		`${formatDate(point.date)}`,
		`<b>${formatValue(point.value)}</b>`
	]
	if (point.label) {
		tooltipLines.push(`<b>${point.label}</b>`)
	}
	return `<div class="lineTooltip">${tooltipLines.join('<p>')}</div>`
}

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

	observer = new IntersectionObserver(
		(entries) => {
			entries.forEach((entry) => {
				if (entry.isIntersecting && !isInView.value) {
					isInView.value = true
					setTimeout(() => {
						startAnimation()
					}, 100 + props.animationStartDelay)
				}
			})
		},
		{
			threshold: 0.3,
			rootMargin: '50px'
		}
	)

	if (chartRef.value) {
		observer.observe(chartRef.value)
	} else {
		setTimeout(() => {
			if (chartRef.value && observer) {
				observer.observe(chartRef.value)
			}
		}, 100)
	}
}

function startAnimation() {
	console.log(`Starting LineChart animation for "${props.title}" (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)

		animatedProgress.value = easeOutCubic(progress)

		if (progress < 1) {
			requestAnimationFrame(animate)
		} else {
			isAnimating.value = false
			console.log(`LineChart animation completed for "${props.title}"`)
		}
	}

	requestAnimationFrame(animate)
}

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

onMounted(() => {
	if (svgRef.value) {
		width.value = svgRef.value.clientWidth || 600
	}

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

onUnmounted(() => {
	if (observer) {
		observer.disconnect()
	}
})
</script>

<template>
	<div ref="chartRef" class="line-chart 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 :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-grow  w-100p relative">
			<svg ref="svgRef" :width="width" :height="height" class="chart-svg h-100p w-100p">
				<!-- Grid lines -->
				<g class="grid">
					<line v-for="line in gridLines" :key="line.y" :x1="paddingLeft" :y1="padding.top + line.y" :x2="paddingLeft + chartWidth" :y2="padding.top + line.y" stroke="#e0e0e0" stroke-width="1" />
					<!-- Y-axis labels -->
					<text v-for="line in gridLines" :key="`label-${line.y}`" :x="labelXPosition" :y="padding.top + line.y + 4" class="grid-label" :text-anchor="labelTextAnchor">
						{{ formatValue(line.value) }}
					</text>
				</g>

				<!-- X-axis -->
				<line :x1="paddingLeft" :y1="padding.top + chartHeight" :x2="paddingLeft + chartWidth" :y2="padding.top + chartHeight" stroke="#ccc" stroke-width="2" />

				<!-- Y-axis -->
				<line :x1="paddingLeft" :y1="padding.top" :x2="paddingLeft" :y2="padding.top + chartHeight" stroke="#ccc" stroke-width="2" />

				<!-- Line path -->
				<path :d="pathData" :stroke="color" stroke-width="3" fill="none" stroke-linecap="round" stroke-linejoin="round" />

				<!-- Data points -->
				<g v-if="showPoints">
					<circle
						v-for="(point, index) in visiblePoints" :key="index" v-tooltip="{ content: formatTooltip(point), html: true }" :cx="paddingLeft + xScale(index)"
						:cy="padding.top + yScale(point.value)" r="4" :fill="color" class="data-point"
					/>
				</g>

				<!-- X-axis labels -->
				<g class="x-labels">
					<text
						v-for="(point, index) in visiblePoints.filter((_, i) => i % Math.ceil(visiblePoints.length / 6) === 0)" :key="index"
						:x="paddingLeft + xScale(visiblePoints.findIndex(d => d === point))" :y="padding.top + chartHeight + 15" class="axis-label" text-anchor="middle"
					>
						{{ formatDate(point.date) }}
					</text>
				</g>
			</svg>
		</div>
	</div>
</template>

<style scoped>
.line-chart,
.chart-container {
	direction: inherit;
}

.chart-svg {
	transform-origin: center;
	display: block;
	/* Remove any inline spacing */
}

.chart-container {
	overflow: hidden;
	/* Prevent any overflow spacing */
}

.grid-label,
.axis-label {
	fill: var(--bgl-gray) !important;
	;
	font-family: system-ui, -apple-system, sans-serif;
	font-size: 12px;
	margin: 1rem;
}

.axis-label {
	text-anchor: middle;
}

.data-point {
	cursor: pointer;
	transition: r 0.2s ease;
}

.data-point:hover {
	r: 6;
}

[dir="rtl"] .line-chart {
	text-align: right;
}
</style>

<style>
.lineTooltip p {
	font-weight: 300 !important;
	font-size: 12px;
}

.lineTooltip {
	font-weight: 700 !important;
}

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