<script setup lang="ts">
/**
 * Gauge — radial progress for a single value (0–max). Great for KPIs, capacity,
 * scores. Defaults to a 270° arc; pass `full` for a complete ring.
 *
 *   <Gauge :value="72" />
 *   <Gauge :value="4.6" :max="5" color="green" label="Rating" suffix="/5" />
 */
import { computed, ref } from 'vue'
import { alpha, resolveColor } from './core/palette'
import { formatValue } from './core/format'
import { useChartAnim } from './core/useChartAnim'

defineOptions({ name: 'BglGauge' })

const props = withDefaults(defineProps<{
	value: number
	max?: number
	min?: number
	size?: number
	thickness?: number
	color?: string
	label?: string
	/** Full 360° ring instead of a 270° gauge. */
	full?: boolean
	/** Show the value text in the center. Default true. */
	showValue?: boolean
	prefix?: string
	suffix?: string
	animated?: boolean
}>(), {
	max: 100,
	min: 0,
	size: 160,
	thickness: 12,
	showValue: true,
	animated: true,
})

const el = ref<HTMLElement>()
const { progress } = useChartAnim({ el, enabled: props.animated, duration: 900 })

const stroke = computed(() => resolveColor(props.color))
const r = computed(() => (props.size - props.thickness) / 2)
const cx = computed(() => props.size / 2)
const arcSpan = computed(() => (props.full ? 360 : 270))
const startAngle = computed(() => (props.full ? -90 : 135)) // degrees

const frac = computed(() => {
	const range = props.max - props.min || 1
	return Math.min(1, Math.max(0, (props.value - props.min) / range))
})

function polar(angleDeg: number): { x: number; y: number } {
	const a = (angleDeg * Math.PI) / 180
	return { x: cx.value + r.value * Math.cos(a), y: cx.value + r.value * Math.sin(a) }
}

function arcPath(fraction: number): string {
	const span = arcSpan.value * fraction
	if (span <= 0) return ''
	const a0 = startAngle.value
	const a1 = startAngle.value + span
	const p0 = polar(a0)
	const p1 = polar(a1)
	const large = span > 180 ? 1 : 0
	return `M ${p0.x} ${p0.y} A ${r.value} ${r.value} 0 ${large} 1 ${p1.x} ${p1.y}`
}

const trackPath = computed(() => arcPath(1))
const valuePath = computed(() => arcPath(frac.value * progress.value))
const valueText = computed(() => formatValue(props.value, { prefix: props.prefix, suffix: props.suffix }))
</script>

<template>
	<div ref="el" class="bgl-gauge relative inline-block" :style="{ width: `${size}px`, height: `${size}px` }">
		<svg :width="size" :height="size" :viewBox="`0 0 ${size} ${size}`" class="display-block">
			<path :d="trackPath" :stroke="alpha(stroke, 14)" :stroke-width="thickness" fill="none" stroke-linecap="round" />
			<path :d="valuePath" :stroke="stroke" :stroke-width="thickness" fill="none" stroke-linecap="round" />
		</svg>
		<div v-if="showValue || label" class="absolute-fill flex-center column pointer-events-none gap-025">
			<span v-if="showValue" class="semibold txt24 line-height-1">{{ valueText }}</span>
			<span v-if="label" class="color-gray txt12">{{ label }}</span>
		</div>
	</div>
</template>

<style scoped>
/* Layout, sizing and text all come from utility classes in the template. */
</style>
