import { computed, getCurrentScope, onScopeDispose, ref, unref, watch } from 'vue'

export const DEFAULT_MIN_VISIBLE_MS = 650

function resolveBooleanSource(source) {
  return Boolean(typeof source === 'function' ? source() : unref(source))
}

function resolveMinVisibleMs(value) {
  const nextValue = Number(value)
  return Number.isFinite(nextValue) && nextValue >= 0 ? nextValue : DEFAULT_MIN_VISIBLE_MS
}

export function useMinimumVisibleState(source, options = {}) {
  const minVisibleMs = computed(() => resolveMinVisibleMs(unref(options.minVisibleMs)))
  const visible = ref(resolveBooleanSource(source))
  let visibleStartedAt = visible.value ? Date.now() : 0
  let hideTimer = null

  function clearHideTimer() {
    if (!hideTimer) {
      return
    }

    globalThis.clearTimeout(hideTimer)
    hideTimer = null
  }

  function show() {
    clearHideTimer()

    if (!visible.value) {
      visibleStartedAt = Date.now()
      visible.value = true
    }
  }

  function hide() {
    clearHideTimer()

    if (!visible.value) {
      return
    }

    const remainingMs = Math.max(0, minVisibleMs.value - (Date.now() - visibleStartedAt))
    if (remainingMs <= 0) {
      visible.value = false
      return
    }

    hideTimer = globalThis.setTimeout(() => {
      hideTimer = null
      visible.value = false
    }, remainingMs)
  }

  const stopWatch = watch(
    () => resolveBooleanSource(source),
    (active) => {
      if (active) {
        show()
        return
      }

      hide()
    },
    { immediate: true }
  )

  if (getCurrentScope()) {
    onScopeDispose(() => {
      clearHideTimer()
      stopWatch()
    })
  }

  return visible
}
