<script setup lang="ts">
import { ref, computed, onMounted } from "vue";

const props = withDefaults(
  defineProps<{ speed: string; size?: number }>(),
  { size: 140 },
);

const animatedValue = ref(0);

// Parse speed to get a normalized value (0-1) for indicator position
// Uses logarithmic curve: fast climb for lower speeds, diminishing impact for higher speeds
const getSpeedValue = (speedStr: string): number => {
  const lower = speedStr.toLowerCase();
  let mbps: number;

  if (lower.includes("gbps")) {
    mbps = parseFloat(speedStr) * 1000; // Convert Gbps to Mbps
  } else {
    mbps = parseFloat(speedStr);
  }

  // Logarithmic curve: log(1 + x * k) / log(1 + k)
  // Higher k = faster climb for lower speeds, compressed difference at higher speeds
  const maxSpeed = 3500;
  const k = 50; // Higher value for more aggressive lower speed progression
  const normalized = Math.min(mbps / maxSpeed, 1);

  return Math.log(1 + normalized * k) / Math.log(1 + k);
};

const targetValue = computed(() => getSpeedValue(props.speed));

// Animate on mount
onMounted(() => {
  const duration = 1200;
  const startTime = performance.now();

  const animate = (currentTime: number) => {
    const elapsed = currentTime - startTime;
    const progress = Math.min(elapsed / duration, 1);

    // Ease-out cubic for smooth deceleration
    const eased = 1 - Math.pow(1 - progress, 3);
    animatedValue.value = eased * targetValue.value;

    if (progress < 1) {
      requestAnimationFrame(animate);
    }
  };

  requestAnimationFrame(animate);
});

// Parse speed into number and unit
const speedNumber = computed(() => parseFloat(props.speed));
const speedUnit = computed(() =>
  props.speed.toLowerCase().includes("gbps") ? "Gbps" : "Mbps",
);

const strokeWidth = 14;
const radius = computed(() => (props.size - strokeWidth) / 2);
const center = computed(() => props.size / 2);

// Arc path for the gauge
const polarToCartesian = (cx: number, cy: number, r: number, angleDeg: number) => {
  const rad = ((angleDeg - 90) * Math.PI) / 180;
  return {
    x: cx + r * Math.cos(rad),
    y: cy + r * Math.sin(rad),
  };
};

const describeArc = (cx: number, cy: number, r: number, startAngle: number, endAngle: number) => {
  const start = polarToCartesian(cx, cy, r, endAngle);
  const end = polarToCartesian(cx, cy, r, startAngle);
  const largeArcFlag = endAngle - startAngle <= 180 ? "0" : "1";
  return `M ${start.x} ${start.y} A ${r} ${r} 0 ${largeArcFlag} 0 ${end.x} ${end.y}`;
};

// Full arc from -135 to 135 (270 degrees)
const arcPath = computed(() => describeArc(center.value, center.value, radius.value, -135, 135));

// Filled arc based on animated value
const filledAngle = computed(() => -135 + animatedValue.value * 270);
const filledArcPath = computed(() =>
  describeArc(center.value, center.value, radius.value, -135, filledAngle.value),
);

// Position for the indicator circle
const indicatorPos = computed(() =>
  polarToCartesian(center.value, center.value, radius.value, filledAngle.value),
);

const uniqueId = computed(() => `speedGradient-${props.speed.replace(/\s/g, "-")}`);

// Gradient with lighter green tones
const colors = { start: "#34d399", mid: "#4ade80", end: "#86efac" };
</script>

<template>
  <div class="relative flex flex-col items-center" :style="{ width: `${size}px`, height: `${size * 0.7}px` }">
    <svg
      :viewBox="`0 0 ${size} ${size}`"
      :width="size"
      :height="size * 0.7"
      class="overflow-visible"
    >
      <defs>
        <linearGradient :id="uniqueId" x1="0%" y1="100%" x2="100%" y2="0%">
          <stop offset="0%" :stop-color="colors.start" />
          <stop offset="50%" :stop-color="colors.mid" />
          <stop offset="100%" :stop-color="colors.end" />
        </linearGradient>
        <filter :id="`shadow-${uniqueId}`" x="-50%" y="-50%" width="200%" height="200%">
          <feDropShadow dx="0" dy="2" stdDeviation="3" flood-opacity="0.35" />
        </filter>
      </defs>

      <!-- Background arc (grey) -->
      <path
        :d="arcPath"
        fill="none"
        stroke="hsl(var(--muted))"
        :stroke-width="strokeWidth"
        stroke-linecap="round"
      />

      <!-- Colored gradient arc -->
      <path
        :d="filledArcPath"
        fill="none"
        :stroke="`url(#${uniqueId})`"
        :stroke-width="strokeWidth / 2"
        stroke-linecap="round"
      />

      <!-- Indicator circle with shadow -->
      <g :filter="`url(#shadow-${uniqueId})`">
        <circle
          :cx="indicatorPos.x"
          :cy="indicatorPos.y"
          :r="10"
          fill="hsl(var(--muted))"
        />
        <circle
          :cx="indicatorPos.x"
          :cy="indicatorPos.y"
          :r="8"
          fill="white"
        />
      </g>

      <!-- Speed number - large -->
      <text
        :x="center"
        :y="center"
        text-anchor="middle"
        dominant-baseline="middle"
        class="fill-primary font-bold"
        :style="{ fontSize: `${size * 0.35}px`, letterSpacing: '-0.05em' }"
      >
        {{ speedNumber }}
      </text>

      <!-- Speed unit - small -->
      <text
        :x="center"
        :y="center + size * 0.20"
        text-anchor="middle"
        class="fill-muted-foreground font-medium"
        :style="{ fontSize: `${size * 0.12}px` }"
      >
        {{ speedUnit }}
      </text>
    </svg>
  </div>
</template>
