/**
 * Knob discovery registry.
 *
 * Stores prototype and component knob definitions generated by the Vite data
 * plugin and exposes synchronous lookup helpers for consumers and hooks.
 */

let prototypeKnobs = {}
let componentKnobs = {}

function normalizeScope(route) {
  if (route == null || route === '' || route === '/') return undefined
  const normalized = String(route).startsWith('/') ? String(route) : `/${route}`
  return normalized.replace(/\/+$/, '') || undefined
}

function flattenKnobs(knobs, parentId = '', inheritedScope) {
  if (!Array.isArray(knobs)) return []

  const result = []
  for (const def of knobs) {
    if (!def || typeof def !== 'object' || typeof def.id !== 'string') continue

    const id = parentId ? `${parentId}.${def.id}` : def.id
    const scope = def.scope ?? inheritedScope
    const flattened = { ...def, id }
    delete flattened.knobs
    if (flattened.scope == null && scope != null) flattened.scope = scope
    result.push(flattened)

    if (Array.isArray(def.knobs)) {
      result.push(...flattenKnobs(def.knobs, id, scope))
    }
  }

  return result
}

function cloneKnobs(knobs) {
  return knobs.map(def => ({ ...def }))
}

function readPrototypeKnobs(value) {
  if (Array.isArray(value)) return value
  if (Array.isArray(value?.meta?.knobs)) return value.meta.knobs
  if (Array.isArray(value?.knobs)) return value.knobs
  return []
}

function readComponentKnobs(value) {
  if (Array.isArray(value)) return value
  if (Array.isArray(value?.knobs)) return value.knobs
  if (Array.isArray(value?.meta?.knobs)) return value.meta.knobs
  return []
}

function normalizeKnobMap(map, readKnobs) {
  const result = {}
  for (const [name, value] of Object.entries(map || {})) {
    result[name] = flattenKnobs(readKnobs(value))
  }
  return result
}

/**
 * Seed the knob registry from generated virtual-module data.
 *
 * @param {{ prototypeKnobs?: object, componentKnobs?: object }} index
 */
export function initKnobs(index = {}) {
  prototypeKnobs = normalizeKnobMap(index.prototypeKnobs, readPrototypeKnobs)
  componentKnobs = normalizeKnobMap(index.componentKnobs, readComponentKnobs)
}

/**
 * Return flattened knobs for a prototype.
 *
 * @param {string} protoName
 * @returns {Array<object>}
 */
export function getPrototypeKnobs(protoName) {
  return cloneKnobs(prototypeKnobs[protoName] || [])
}

/**
 * Return flattened knobs for a component.
 *
 * @param {string} componentName
 * @returns {Array<object>}
 */
export function getComponentKnobs(componentName) {
  return cloneKnobs(componentKnobs[componentName] || [])
}

/**
 * Resolve a knob definition by id and route scope.
 *
 * @param {string} id
 * @param {{ route?: string|null, knobs?: Array<object> }} [options]
 * @returns {object|undefined}
 */
export function resolveKnobDef(id, { route, knobs = [] } = {}) {
  const normalizedRoute = normalizeScope(route)
  return flattenKnobs(knobs).find(def =>
    def.id === id && normalizeScope(def.scope) === normalizedRoute
  )
}

export { flattenKnobs, normalizeScope }
