/**
 * Read-time migration for FontAsset records (docs/architecture/02 §4).
 *
 * Mirrors snippet/dataset/theme migrations: every font read from storage passes
 * through `migrateFontAsset`, which fills missing/invalid fields and stamps the
 * current version. Unknown fields are tolerated (spread the original, only fill
 * gaps) so a record written by a newer build round-trips without loss.
 */

import {
  CURRENT_FONT_VERSION,
  detectFontFormat,
  type FontAsset,
  type FontAxis,
  type FontFormat,
  type FontSource,
} from '@core/font-asset';

const FORMATS: ReadonlyArray<FontFormat> = ['woff2', 'woff', 'ttf', 'otf'];

/** Accept a stored `axes` array only if it's shaped like FontAxis records. */
function migrateAxes(raw: unknown): FontAxis[] | undefined {
  if (!Array.isArray(raw)) return undefined;
  const axes = raw.filter(
    (a): a is FontAxis =>
      !!a &&
      typeof (a as FontAxis).tag === 'string' &&
      typeof (a as FontAxis).min === 'number' &&
      typeof (a as FontAxis).max === 'number',
  );
  return axes.length > 0 ? axes : undefined;
}

/** Upgrade a raw stored record to the current FontAsset shape. */
export function migrateFontAsset(raw: unknown): FontAsset {
  const r = { ...(raw as Record<string, unknown>) };
  const fileName = typeof r.fileName === 'string' ? r.fileName : '';
  const format: FontFormat = FORMATS.includes(r.format as FontFormat)
    ? (r.format as FontFormat)
    : (detectFontFormat(fileName) ?? 'woff2');
  const data = r.data instanceof ArrayBuffer ? r.data : new ArrayBuffer(0);
  const source: FontSource = r.source === 'google' ? 'google' : 'file';
  const axes = migrateAxes(r.axes);
  delete r.axes; // re-attach the validated value below (or omit it entirely)
  return {
    ...r,
    id: typeof r.id === 'number' ? r.id : Number(r.id),
    version: CURRENT_FONT_VERSION,
    family: typeof r.family === 'string' ? r.family : 'Custom font',
    data,
    format,
    fileName,
    source,
    ...(axes ? { axes } : {}),
    size: typeof r.size === 'number' ? r.size : data.byteLength,
    created: typeof r.created === 'string' ? r.created : new Date(0).toISOString(),
    modified: typeof r.modified === 'string' ? r.modified : new Date(0).toISOString(),
  };
}
