<template>
  <div
    :aria-valuemax="max"
    :aria-valuemin="min"
    :aria-valuenow="progress !== 'indeterminate' ? progress : undefined"
    :aria-valuetext="
      percentage ? `${percentage.toLocaleString(locale, { maximumFractionDigits: 2 })}%` : undefined
    "
    role="progressbar"
  >
    <svg
      class="tw-aspect-square tw-max-w-full tw-max-h-full"
      height="120"
      viewBox="0 0 120 120"
      width="120"
      xmlns="http://www.w3.org/2000/svg"
    >
      <g>
        <g class="circle" :class="{ indeterminate: progress === 'indeterminate' }">
          <circle class="track" cx="60" cy="60" fill="none" r="54" stroke-width="12" />
          <circle
            class="value"
            :stroke-dashoffset="dashOffset"
            cx="60"
            cy="60"
            fill="none"
            pathLength="100"
            r="54"
            stroke="currentColor"
            stroke-dasharray="100"
            stroke-width="12"
          />
        </g>
        <text
          v-if="percentage"
          x="50%"
          y="52.5%"
          dominant-baseline="middle"
          text-anchor="middle"
          font-size="200%"
        >
          {{ `${Math.round(percentage)}%` }}
        </text>
      </g>
    </svg>
  </div>
</template>

<script lang="ts" setup>
import { computed } from 'vue'
import { useI18n } from '@/i18n'

const progress = defineModel<number | 'indeterminate'>('progress', { required: true })
const props = withDefaults(
  defineProps<{
    min?: number
    max?: number
  }>(),
  {
    min: 0,
    max: 100,
  },
)
const { locale } = useI18n()

const percentage = computed(() => {
  if (progress.value === 'indeterminate') return null

  if (progress.value < props.min) {
    return 0
  } else if (progress.value > props.max) {
    return 100
  }

  return ((progress.value - props.min) / (props.max - props.min)) * 100
})

const dashOffset = computed(() => 100 - (percentage.value ?? 0))
</script>

<style lang="postcss" scoped>
.track {
  stroke: theme('colors.gray.100');
  stroke: color-mix(in oklab, currentColor 15%, transparent 10%);
}

.value {
  transition: stroke-dashoffset 0.2s;
}

.circle {
  @apply tw-origin-center;

  &:not(.indeterminate) {
    @apply tw-translate-x-0 tw-translate-y-0 tw-skew-x-0 tw-skew-y-0 tw-scale-100 -tw-rotate-90;
  }

  &.indeterminate {
    animation: tw-spin 1s linear infinite;

    & > .value {
      animation: stretch 3s linear infinite;
    }
  }
}

@keyframes stretch {
  0%,
  50%,
  100% {
    stroke-dashoffset: 90;
  }
  25%,
  75% {
    stroke-dashoffset: 65;
  }
}
</style>