import type { CapabilityDefinition } from './types';

/**
 * Declarative map of server-side features, the strategies that can provide them
 * per server generation, how to detect each, and which endpoint to route to.
 *
 * To add a feature with a new server path:
 *   1. (optional) register a probe in `probes.ts` and map it in the orchestrator
 *      (`api/subsonic.ts`) + read facade (`storeView.ts`).
 *   2. add a `CapabilityDefinition` here with one strategy per server generation.
 *   3. consumers read it via `storeView` (UI) and the call router (runtime).
 * No version `if` checks belong in UI or call sites — they live here.
 */

export const SONIC_SIMILARITY_EXTENSION = 'sonicSimilarity';
export const PLAYBACK_REPORT_EXTENSION = 'playbackReport';
export const SONG_LYRICS_EXTENSION = 'songLyrics';

export const FEATURE_AUDIOMUSE_SIMILAR_TRACKS = 'audiomuse.similarTracks';
export const FEATURE_PLAYBACK_REPORT = 'opensubsonic.playbackReport';
export const FEATURE_ENHANCED_LYRICS = 'opensubsonic.enhancedLyrics';

export const PROBE_OPENSUBSONIC_EXTENSIONS = 'opensubsonic.extensions';
export const PROBE_LEGACY_INSTANT_MIX = 'navidrome.instantMix.legacy';

/** Operation names used by the call router. */
export const OP_SIMILAR_TRACKS = 'similarTracks';
export const OP_REPORT_PLAYBACK = 'reportPlayback';
export const OP_GET_LYRICS = 'getLyrics';

export const SERVER_CAPABILITY_CATALOG: CapabilityDefinition[] = [
  {
    feature: FEATURE_AUDIOMUSE_SIMILAR_TRACKS,
    labelKey: 'settings.audiomuseTitle',
    badgeLabelKey: 'settings.audiomuseBadge',
    strategies: [
      {
        // Navidrome ≥ 0.62: AudioMuse plugin advertised via OpenSubsonic.
        id: 'opensubsonic.sonicSimilarity',
        priority: 100,
        when: (ctx) => ctx.isNavidrome && ctx.semverGte([0, 62, 0]),
        detection: {
          kind: 'extension',
          probeId: PROBE_OPENSUBSONIC_EXTENSIONS,
          extension: SONIC_SIMILARITY_EXTENSION,
        },
        trust: 'high',
        activation: 'auto',
        calls: {
          [OP_SIMILAR_TRACKS]: { endpoint: 'getSonicSimilarTracks.view', transport: 'opensubsonic' },
        },
        labelKey: 'settings.audiomuseStrategySonic',
      },
      {
        // Navidrome ≥ 0.60: legacy Instant Mix via getSimilarSongs (agents/plugin).
        id: 'subsonic.getSimilarSongs',
        priority: 50,
        when: (ctx) => ctx.isNavidrome && ctx.semverGte([0, 60, 0]),
        detection: {
          kind: 'functional',
          probeId: PROBE_LEGACY_INSTANT_MIX,
          presentWhen: (outcome) => outcome.status === 'present',
        },
        trust: 'low',
        activation: 'manual',
        alwaysCallable: true,
        calls: {
          [OP_SIMILAR_TRACKS]: { endpoint: 'getSimilarSongs.view', transport: 'subsonic' },
        },
        labelKey: 'settings.audiomuseStrategyLegacy',
      },
    ],
  },
  {
    // OpenSubsonic `playbackReport` (Navidrome ≥ 0.62): rich live now-playing via
    // a small playback FSM. Auto-on wherever the server advertises the extension;
    // call sites fall back to legacy `scrobble.view?submission=false` presence when
    // it is absent. Detection is server-agnostic (any OpenSubsonic server may add it).
    feature: FEATURE_PLAYBACK_REPORT,
    labelKey: 'nowPlaying.title',
    strategies: [
      {
        id: 'opensubsonic.playbackReport',
        priority: 100,
        when: (ctx) => ctx.openSubsonic,
        detection: {
          kind: 'extension',
          probeId: PROBE_OPENSUBSONIC_EXTENSIONS,
          extension: PLAYBACK_REPORT_EXTENSION,
        },
        trust: 'high',
        activation: 'auto',
        calls: {
          [OP_REPORT_PLAYBACK]: { endpoint: 'reportPlayback.view', transport: 'opensubsonic' },
        },
        labelKey: 'nowPlaying.title',
      },
    ],
  },
  {
    // OpenSubsonic `songLyrics` v2 (`enhanced=true`): word/syllable cues for
    // karaoke highlighting, plus translation/pronunciation layers we filter out.
    //
    // The extension probe stores names only, not advertised versions, so the
    // version gate rides on the server identity instead: Navidrome ships v2 in
    // 0.63.0. That deliberately keeps `enhanced` off for every non-Navidrome
    // server — the parameter is additive, but no spec forces a v1 server to
    // ignore an unknown one, and a 400 would take lyrics down entirely.
    feature: FEATURE_ENHANCED_LYRICS,
    labelKey: 'settings.lyricsSourceServer',
    strategies: [
      {
        id: 'opensubsonic.songLyricsEnhanced',
        priority: 100,
        when: (ctx) => ctx.isNavidrome && ctx.semverGte([0, 63, 0]),
        detection: {
          kind: 'extension',
          probeId: PROBE_OPENSUBSONIC_EXTENSIONS,
          extension: SONG_LYRICS_EXTENSION,
        },
        trust: 'high',
        activation: 'auto',
        calls: {
          [OP_GET_LYRICS]: { endpoint: 'getLyricsBySongId.view', transport: 'opensubsonic' },
        },
        labelKey: 'settings.lyricsSourceServer',
      },
    ],
  },
];

export function getCapabilityDefinition(feature: string): CapabilityDefinition | undefined {
  return SERVER_CAPABILITY_CATALOG.find((d) => d.feature === feature);
}
