// Enabled-plugin gating for the router. Fetches the enabled plugin-name list
// ONCE (cached promise) so a disabled backend plugin's frontend routes become
// unreachable by direct URL. Fail-open: any fetch error treats every plugin as
// enabled, so an API blip can never brick navigation.
import { pluginsApi } from '../api'

let enabledPromise = null
let enabledSet = null // resolved Set<string>, or null while pending / on failure

// The router AWAITS this, so it must never outlast a navigation. An app-pool
// restart leaves requests hanging (IIS queues them while the worker starts) and
// axios has no timeout, so an unbounded wait here froze navigation outright -
// and because the promise was cached, every later navigation awaited the same
// hung request and stayed frozen after the backend recovered.
const GATE_TIMEOUT_MS = 4000

// Kick off (or reuse) the single fetch. The endpoint is jwt-optional so this
// works on unauthenticated kiosk routes (e.g. /tv) too.
export function loadEnabledPlugins() {
  if (!enabledPromise) {
    const fetched = pluginsApi.enabled()
      .then(response => {
        const names = response?.data?.data
        // Only trust a real array; anything else -> fail open (null).
        enabledSet = Array.isArray(names) ? new Set(names) : null
        return enabledSet
      })
      .catch(() => {
        // Fail open: leave enabledSet null so isPluginEnabled returns true.
        enabledSet = null
        return null
      })

    // Bounded wait, fail-open on expiry. A timed-out or failed attempt drops the
    // cached promise so the NEXT navigation retries instead of inheriting a dead
    // one; a request that lands late still populates enabledSet.
    let timer
    const bounded = new Promise(resolve => {
      timer = setTimeout(() => resolve(null), GATE_TIMEOUT_MS)
    })
    enabledPromise = Promise.race([fetched, bounded]).then(result => {
      clearTimeout(timer)
      if (result === null) enabledPromise = null
      return result
    })
  }
  return enabledPromise
}

// True if the plugin is enabled OR the list is unknown (fail-open). A null
// enabledSet means we never got a trustworthy answer, so allow everything.
export function isPluginEnabled(name) {
  if (!name) return true
  if (enabledSet === null) return true
  return enabledSet.has(name)
}

// Test/hot-reload hook: forget the cached result so the next call refetches.
export function resetEnabledPlugins() {
  enabledPromise = null
  enabledSet = null
}
