/**
 * Image-sticker manifest.
 *
 * Stickers are PNG/WebP/JPG/SVG files dropped into `public/stickers/` with a
 * specific filename convention:
 *
 *   <category>__<sticker_name>.<ext>
 *
 * Examples:
 *   hearts__pink_heart.png       → category: Hearts, name: Pink Heart
 *   pets__golden_retriever.png   → category: Pets,   name: Golden Retriever
 *
 * Adding a sticker is zero-config: drop the file in `public/stickers/`, name
 * it correctly, refresh the page. No imports to edit, no manifest to update.
 *
 * The filename list comes from a Vite virtual module (see
 * `stickerManifestPlugin` in vite.config.js). Vite's import.meta.glob can't
 * see `public/`, so the plugin reads the directory at build time and emits
 * the list. URLs are stable and unhashed (`/stickers/<filename>`), which
 * lets the server also read these files during export — see
 * `resolveImageSource` in server.js for that path.
 *
 * If `public/stickers/` is empty, this module exports empty arrays and the
 * StickersTab renders a friendly empty state. No crash, no noisy console.
 */

import { STICKER_FILES } from 'virtual:sticker-manifest';

// Public URL base for sticker assets. The Vite plugin watches the matching
// directory on disk; the server reads from the same prefix on its side.
const STICKER_URL_PREFIX = '/stickers/';

/**
 * Parse a filename into display metadata.
 *
 * Filename shape: `[<sort>-]<category>__<name>.<ext>` where:
 *   - <sort>     (optional) leading "<digits>-" prefix used only for category ordering
 *   - <category> lowercase word, no underscores within
 *   - <name>     one or more underscore-separated words
 *
 * Returns null for files that don't match (e.g. files lacking `__`). Returning
 * null rather than throwing lets the module evaluate cleanly even if someone
 * accidentally drops a stray file into the folder.
 */
function parseStickerFilename(filename) {
  const dotIdx = filename.lastIndexOf('.');
  if (dotIdx <= 0) return null;
  const base = filename.slice(0, dotIdx);

  // Optional "<digits>-" prefix for explicit ordering.
  let sortKey = '';
  let rest = base;
  const dashMatch = base.match(/^(\d+)-(.+)$/);
  if (dashMatch) {
    // Pad so '2' sorts before '10' lexicographically.
    sortKey = dashMatch[1].padStart(6, '0');
    rest = dashMatch[2];
  }

  // Split on the DOUBLE underscore. Exactly one expected; if missing or
  // duplicated, the file isn't a valid sticker.
  const parts = rest.split('__');
  if (parts.length !== 2) return null;
  const [categorySlug, nameSlug] = parts;
  if (!categorySlug || !nameSlug) return null;

  return {
    categoryId: categorySlug.toLowerCase(),
    categoryLabel: titleCase(categorySlug),
    name: titleCase(nameSlug),
    sortKey,
  };
}

function titleCase(slug) {
  return slug
    .split('_')
    .filter(Boolean)
    .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
    .join(' ');
}

/**
 * Build the sticker list. One pass over the filename list from the virtual
 * module; each valid file becomes a sticker with `{ id, url, name,
 * categoryId, categoryLabel }`.
 *
 * `id` is derived from the URL because the URL is unique per file and stable
 * enough across reloads to use as a React key. We don't persist sticker ids
 * anywhere — once a sticker is added to the canvas, the relevant identity is
 * the canvas element's id, not the source sticker's.
 */
function buildStickerList() {
  const out = [];
  for (const filename of STICKER_FILES) {
    const parsed = parseStickerFilename(filename);
    if (!parsed) continue;
    const url = STICKER_URL_PREFIX + filename;
    out.push({
      id: url,
      url,
      name: parsed.name,
      categoryId: parsed.categoryId,
      categoryLabel: parsed.categoryLabel,
      sortKey: parsed.sortKey,
    });
  }
  return out;
}

const _all = buildStickerList();

/**
 * All sticker entries, sorted by (category sortKey, sticker name). The
 * category sort key is derived from the lowest `sortKey` seen for that
 * category — if any file in the category has a `<digits>-` prefix, the
 * whole category gets ordered by it; otherwise alphabetical.
 */
export const STICKERS = (() => {
  // Resolve a stable sort key per category: lowest seen `sortKey` (already
  // zero-padded) for files in that category. Falls back to the category
  // label for purely alphabetical ordering.
  const catKey = new Map();
  for (const s of _all) {
    const existing = catKey.get(s.categoryId);
    if (!existing || (s.sortKey && (!existing.sortKey || s.sortKey < existing.sortKey))) {
      catKey.set(s.categoryId, { sortKey: s.sortKey || '', label: s.categoryLabel });
    }
  }
  return [..._all].sort((a, b) => {
    const ka = catKey.get(a.categoryId);
    const kb = catKey.get(b.categoryId);
    const keyA = (ka.sortKey || 'zzz') + '|' + ka.label.toLowerCase();
    const keyB = (kb.sortKey || 'zzz') + '|' + kb.label.toLowerCase();
    if (keyA !== keyB) return keyA < keyB ? -1 : 1;
    return a.name.localeCompare(b.name);
  });
})();

/**
 * Deduped list of categories, in display order. Each entry is
 * `{ id, label }`. The Stickers tab adds an implicit "All" pill at the
 * front itself — that's a tab concern, not a data one.
 */
export const STICKER_CATEGORIES = (() => {
  const seen = new Set();
  const out = [];
  for (const s of STICKERS) {
    if (seen.has(s.categoryId)) continue;
    seen.add(s.categoryId);
    out.push({ id: s.categoryId, label: s.categoryLabel });
  }
  return out;
})();
