// Whisper model catalog plus a small device-aware recommendation policy.
// Pure data + functions: no platform, no I/O. Downstream UI and the engine
// loader read from MODELS to know download sizes, repos, and ggml filenames.

import type { ModelId, Backend } from '../types';

/** Rough capability bucket for a model, used for UX grouping and sorting. */
export type ModelTier = 'fast' | 'balanced' | 'accurate';

/** Static metadata describing a single Whisper model variant. */
export interface ModelInfo {
  /** Canonical model id (matches its key in {@link MODELS}). */
  id: ModelId;
  /** Human-friendly display name. */
  label: string;
  /** Speed/accuracy bucket. */
  tier: ModelTier;
  /** True for the general multilingual variants; false for `.en` (English-only). */
  multilingual: boolean;
  /** Approximate on-disk / download size in megabytes (rough, for UX). */
  approxMB: number;
  /** Hugging Face repo for the web/transformers.js backend, e.g. 'Xenova/whisper-tiny.en'. */
  webRepo: string;
  /** ggml binary filename for the native whisper.cpp backend, e.g. 'ggml-tiny.en.bin'. */
  ggml: string;
}

/**
 * The full catalog of supported models, keyed by id. Tiers:
 *   tiny*  -> 'fast', base* -> 'balanced', small* -> 'accurate'.
 * `.en` ids are English-only (multilingual=false); the bare ids are multilingual.
 */
export const MODELS: Record<ModelId, ModelInfo> = {
  'tiny.en': {
    id: 'tiny.en',
    label: 'Tiny (English)',
    tier: 'fast',
    multilingual: false,
    approxMB: 75,
    webRepo: 'Xenova/whisper-tiny.en',
    ggml: 'ggml-tiny.en.bin',
  },
  tiny: {
    id: 'tiny',
    label: 'Tiny',
    tier: 'fast',
    multilingual: true,
    approxMB: 75,
    webRepo: 'Xenova/whisper-tiny',
    ggml: 'ggml-tiny.bin',
  },
  'base.en': {
    id: 'base.en',
    label: 'Base (English)',
    tier: 'balanced',
    multilingual: false,
    approxMB: 145,
    webRepo: 'Xenova/whisper-base.en',
    ggml: 'ggml-base.en.bin',
  },
  base: {
    id: 'base',
    label: 'Base',
    tier: 'balanced',
    multilingual: true,
    approxMB: 145,
    webRepo: 'Xenova/whisper-base',
    ggml: 'ggml-base.bin',
  },
  'small.en': {
    id: 'small.en',
    label: 'Small (English)',
    tier: 'accurate',
    multilingual: false,
    approxMB: 480,
    webRepo: 'Xenova/whisper-small.en',
    ggml: 'ggml-small.en.bin',
  },
  small: {
    id: 'small',
    label: 'Small',
    tier: 'accurate',
    multilingual: true,
    approxMB: 480,
    webRepo: 'Xenova/whisper-small',
    ggml: 'ggml-small.bin',
  },
};

/** The safe out-of-the-box default: fast, small download, no language baggage. */
export const DEFAULT_MODEL: ModelId = 'tiny.en';

/** What we know about the current device's compute path and memory pressure. */
export interface DeviceCaps {
  backend: Backend;
  /** When true, prefer the smallest model regardless of backend. */
  lowMemory?: boolean;
}

/** Backends that have meaningful GPU-class acceleration. */
const GPU_BACKENDS: ReadonlySet<Backend> = new Set<Backend>([
  'webgpu',
  'coreml',
  'metal',
]);

/**
 * Pick a sensible default model for a device.
 * Policy:
 *   - lowMemory                       -> 'tiny.en' (always wins)
 *   - GPU-class backend (webgpu/coreml/metal) -> 'base.en'
 *   - CPU-class backend (cpu/wasm)    -> 'tiny.en'
 * Never recommends a 'small.*' model as a default.
 */
export function recommendModel(caps: DeviceCaps): ModelId {
  if (caps.lowMemory) return 'tiny.en';
  if (GPU_BACKENDS.has(caps.backend)) return 'base.en';
  return 'tiny.en';
}

/** All models in a given tier, in catalog (declaration) order. */
export function modelsByTier(tier: ModelTier): ModelInfo[] {
  return listModels().filter((m) => m.tier === tier);
}

/** All models as a flat list, in catalog (declaration) order. */
export function listModels(): ModelInfo[] {
  return Object.values(MODELS);
}
