import type { AddEntry } from './downloads'

/**
 * A tiny typed event bus that owns the cross-store reactions between the
 * downloads and sources stores (C2). Previously `downloads.ts` imported
 * `useSources` and `sources.ts` imported `useDownloads`, a circular dependency
 * that only worked because both sides reached across lazily via `.getState()`.
 *
 * Now each store depends on this bus instead of on the other: a store *emits* the
 * events it produces and *subscribes* to the ones it consumes. The bus itself has
 * no runtime dependency on either store (the `AddEntry` import is type-only and is
 * erased at build time), so there is no import cycle.
 *
 *   sources  --enqueueDownloads-->  downloads   (queue a channel's media items)
 *   downloads --downloadCompleted--> sources    (mark the source item downloaded)
 *   sources  --sourceRemoved------>  downloads   (cancel that source's in-flight downloads)
 */
export interface StoreEvents {
  /** sources → downloads: enqueue a batch of media items as downloads */
  enqueueDownloads: AddEntry[]
  /** downloads → sources: a download tied to a source MediaItem finished */
  downloadCompleted: { mediaItemId: string; filePath?: string; quality?: string }
  /** sources → downloads: a source was removed; cancel its in-flight downloads (L157) */
  sourceRemoved: string
}

type Handler<K extends keyof StoreEvents> = (payload: StoreEvents[K]) => void

// Heterogeneous handler sets keyed by event name. The `never` payload is the
// standard trick for a per-key event map; the public on/emit signatures keep the
// payload types sound at every call site.
const handlers = new Map<keyof StoreEvents, Set<(payload: never) => void>>()

/** Subscribe to a store event. Returns an unsubscribe function. */
export function on<K extends keyof StoreEvents>(event: K, handler: Handler<K>): () => void {
  let set = handlers.get(event)
  if (!set) {
    set = new Set()
    handlers.set(event, set)
  }
  const erased = handler as (payload: never) => void
  set.add(erased)
  return () => set.delete(erased)
}

/** Dispatch a store event to all current subscribers. */
export function emit<K extends keyof StoreEvents>(event: K, payload: StoreEvents[K]): void {
  const set = handlers.get(event)
  if (!set) return
  for (const handler of set) (handler as Handler<K>)(payload)
}
