// The feed's view vocabulary. Lifted out of Feed (like feedSort.ts) because it has three
// consumers that can't share module-private state: App owns the pref, the toolbar's
// ViewSwitcher offers it, and VirtualFeed/VideoCard render it.
export type FeedView = "cards" | "cardsSmall" | "rows" | "rowsCompact" | "tiles";

export const FEED_VIEWS: readonly FeedView[] = [
  "cards",
  "cardsSmall",
  "rows",
  "rowsCompact",
  "tiles",
] as const;

const FEED_VIEW_DEFAULT: FeedView = "cards";

export interface FeedViewSpec {
  /** Which shape VideoCard renders: a portrait card (thumbnail on top) or a horizontal block. */
  family: "card" | "row";
  /** Narrowest grid column in px, or null for ONE full-width column. VirtualFeed derives the
   * column count from this and the container width, so every multi-column view reflows for free. */
  minCol: number | null;
  /** Single-column views only: the reading-width cap in px (null = fill). A long line is hard to
   * scan, so the stacked row keeps a cap; the one-line row doesn't need as tight a one. */
  maxCol: number | null;
  /** Show the video thumbnail. False only for the bare row — whose badges (duration, live state,
   * saved, resume bar) then move into the meta line, since Thumb is what draws them. */
  thumb: boolean;
  /** card family: tighter padding and no channel avatar, for the small card's ~180px column. */
  dense: boolean;
  /** row family: actions sit under the meta rather than docked at the right edge. Frees ~168px of
   * width (measured), which is what lets a row block survive in a narrow tile column. */
  actionsBelow: boolean;
}

// The whole matrix in one place. Adding a view here makes TS point at every switch that needs it.
export const FEED_VIEW_SPEC: Record<FeedView, FeedViewSpec> = {
  cards: {
    family: "card",
    minCol: 260,
    maxCol: null,
    thumb: true,
    dense: false,
    actionsBelow: false,
  },
  cardsSmall: {
    family: "card",
    minCol: 180,
    maxCol: null,
    thumb: true,
    dense: true,
    actionsBelow: false,
  },
  // Single column on purpose: the point of the list is that your eye runs down one edge with the
  // titles stacked. Density must not cost that — `tiles` is the multi-column option instead.
  // Keeps the 896px cap: its actions dock at the right edge, so a wider row would only stretch the
  // dead space between them and the meta.
  rows: {
    family: "row",
    minCol: null,
    maxCol: 896,
    thumb: true,
    dense: false,
    actionsBelow: false,
  },
  // Much wider (1472): everything sits on one line and the columns after the title are fixed, so
  // there's no gap for the extra width to stretch — it all goes to the title. Raised from 1280 at
  // the user's request once they saw how much room was left over with the rail and filters hidden.
  rowsCompact: {
    family: "row",
    minCol: null,
    maxCol: 1472,
    thumb: false,
    dense: false,
    actionsBelow: false,
  },
  // 380 = thumbnail (160) + gap (12) + ~192 for the text + the block's own padding (16). The text
  // floor is the action row's measured 156px plus enough for a title to be worth reading.
  // Tuned by measuring the real layouts, not guessed: 3 columns need 3n+32 px, so 380 turns the
  // channel page (1208px) and the unpinned feed into 3 columns while the filter-pinned feed
  // (~955px) still gets 2. 470 was tried first and needed 956px for two — the common layout fell
  // back to ONE column and the mode looked broken; 400 then left 596px tiles whose titles ended
  // halfway, which is the very waste this mode exists to kill.
  tiles: {
    family: "row",
    minCol: 380,
    maxCol: null,
    thumb: true,
    dense: false,
    actionsBelow: true,
  },
};

function isFeedView(v: unknown): v is FeedView {
  return typeof v === "string" && (FEED_VIEWS as readonly string[]).includes(v);
}

/** Coerce a stored pref to a view. Up to 0.44 it was "grid" | "list"; those map forward here so
 * nobody's saved choice is lost. Anything else (a corrupt value, a future view rolled back) falls
 * back to the default rather than rendering nothing. */
export function parseFeedView(raw: unknown): FeedView {
  if (isFeedView(raw)) return raw;
  if (raw === "grid") return "cards";
  if (raw === "list") return "rows";
  return FEED_VIEW_DEFAULT;
}
