<script lang="ts">
import type { ButtonHTMLAttributes } from 'vue'
import type { PrimitiveProps } from 'radix-vue'
import type { NuxtLinkProps } from '#app'
import { pick } from '#ui/utils'

export interface LinkProps extends NuxtLinkProps, Omit<PrimitiveProps, 'asChild'> {
  type?: ButtonHTMLAttributes['type']
  disabled?: boolean
  active?: boolean
  exact?: boolean
  exactQuery?: boolean
  exactHash?: boolean
  inactiveClass?: string
}

export function getNuxtLinkProps (props: NuxtLinkProps) {
  return pick(props, ['to', 'href', 'target', 'rel', 'noRel', 'prefetch', 'noPrefetch'])
}
</script>

<script setup lang="ts">
import { isEqual } from 'ohash'
import { Primitive, useForwardProps } from 'radix-vue'
import { reactiveOmit } from '@vueuse/core'
import type { RouteLocation } from '#vue-router'

defineOptions({ inheritAttrs: false })

const props = withDefaults(defineProps<LinkProps>(), { as: 'button', type: 'button', active: undefined })

const nuxtLinkProps = useForwardProps(reactiveOmit(props, 'as', 'type', 'disabled', 'active', 'exact', 'exactQuery', 'exactHash', 'activeClass', 'inactiveClass'))

function resolveLinkClass (route: RouteLocation, currentRoute: RouteLocation, { isActive, isExactActive }: { isActive: boolean, isExactActive: boolean }) {
  if (props.exactQuery && !isEqual(route.query, currentRoute.query)) {
    return props.inactiveClass
  }
  if (props.exactHash && route.hash !== currentRoute.hash) {
    return props.inactiveClass
  }

  if (props.exact && isExactActive) {
    return props.activeClass
  }

  if (!props.exact && isActive) {
    return props.activeClass
  }

  return props.inactiveClass
}
</script>

<template>
  <Primitive
    v-if="!to"
    :as="as"
    :type="type"
    :disabled="disabled"
    v-bind="$attrs"
    :class="active ? activeClass : inactiveClass"
  >
    <slot v-bind="{ active }" />
  </Primitive>
  <NuxtLink v-else v-slot="{ route, href, target, rel, navigate, isActive, isExactActive, isExternal }" v-bind="nuxtLinkProps" custom>
    <a
      v-bind="$attrs"
      :href="!disabled ? href : undefined"
      :aria-disabled="disabled ? 'true' : undefined"
      :role="disabled ? 'link' : undefined"
      :rel="rel"
      :target="target"
      :class="active !== undefined ? (active ? activeClass : inactiveClass) : resolveLinkClass(route, $route, { isActive, isExactActive })"
      @click="(e: any) => (!isExternal && !disabled) && navigate(e)"
    >
      <slot v-bind="{ active: active !== undefined ? active : (exact ? isExactActive : isActive) }" />
    </a>
  </NuxtLink>
</template>
