// nyashelf-data.jsx
// Sample data for figures + utility helpers.
// FigureArt: stylized SVG placeholder card art (no external images — keeps the
// dreamy aesthetic uniform and works offline).

// Prices are stored as base EUR amounts; nyaFormat() converts to selected currency.
// Each figure also carries:
//   category — nin-nin-game.com top-level dept (Figures / Collectibles / TCG / …)
//   tags     — free-form tags for filtering: franchise, character, theme, brand…
//   addedAt  — when added to catalog (drives "Just added")
//   hot      — true if currently in "Hot Pre-orders" / "Hot Products"
const NYA_FIGURES = [
  { id: 'f1', name: 'Hatsuki Yura', line: 'Aria Lullaby', maker: 'Kotobukiya', scale: '1/7',
    price: 189, status: 'preorder', release: '2026-08-15', payDays: 6,  paid: 57,  wishlist: false, hue: 285, tone: 'lilac', char: 'L',
    category: 'figures', addedAt: '2026-05-18', hot: true,
    tags: ['kotobukiya', 'bishoujo', 'idol', 'fantasy', '1/7', 'осень-26'] },
  { id: 'f2', name: 'Tsukimiya Rei', line: 'Moonlit Dance', maker: 'Alter', scale: '1/8',
    price: 145, status: 'preorder', release: '2026-09-30', payDays: 12, paid: 0,   wishlist: false, hue: 320, tone: 'pink', char: 'M',
    category: 'figures', addedAt: '2026-05-12', hot: false,
    tags: ['alter', 'school-life', 'magical-girl', 'kimono', '1/8'] },
  { id: 'f3', name: 'Yumiko Sakura', line: 'Petal Dream',   maker: 'GSC',  scale: '1/7',
    price: 223, status: 'paid',     release: '2026-06-20', payDays: 0,  paid: 223, wishlist: false, hue: 340, tone: 'pink', char: 'S',
    category: 'figures', addedAt: '2026-03-02', hot: false,
    tags: ['good-smile', 'cherry-blossom', 'romance', 'spring', '1/7'] },
  { id: 'f4', name: 'Kana Hoshino',  line: 'Stellar Aria',  maker: 'Max Factory', scale: '1/6',
    price: 268, status: 'shipped',  release: '2026-05-25', payDays: 0,  paid: 268, wishlist: false, hue: 250, tone: 'blue',  char: 'K',
    category: 'figures', addedAt: '2026-02-18', hot: false,
    tags: ['max-factory', 'sci-fi', 'mech', '1/6', 'limited-edition'] },
  { id: 'f5', name: 'Mei Asakura',   line: 'Cherry Wind',   maker: 'Kotobukiya', scale: '1/8',
    price: 128, status: 'soon',     release: '2026-11-12', payDays: 30, paid: 0,   wishlist: true,  hue: 5,   tone: 'rose',  char: 'A',
    category: 'figures', addedAt: '2026-05-20', hot: true,
    tags: ['kotobukiya', 'school-life', 'kimono', 'romance', '1/8'] },
  { id: 'f6', name: 'Hina Mochizuki',line: 'Night Garden',  maker: 'Alter', scale: '1/7',
    price: 195, status: 'preorder', release: '2026-07-10', payDays: 2,  paid: 98,  wishlist: false, hue: 280, tone: 'lilac', char: 'H',
    category: 'figures', addedAt: '2026-04-05', hot: true,
    tags: ['alter', 'fantasy', 'magical-girl', 'limited-edition', '1/7'] },
  { id: 'f7', name: 'Ren Hoshigami', line: 'Velvet Spell',  maker: 'GSC', scale: '1/7',
    price: 210, status: 'preorder', release: '2026-10-05', payDays: 18, paid: 70,  wishlist: false, hue: 300, tone: 'lilac', char: 'R',
    category: 'figures', addedAt: '2026-05-15', hot: false,
    tags: ['good-smile', 'magical-girl', 'witch', 'fantasy', '1/7'] },
  { id: 'f8', name: 'Yui Mizuhara',  line: 'Aurora Whisper',maker: 'Max Factory', scale: '1/8',
    price: 156, status: 'available',release: '2026-04-01', payDays: 0,  paid: 156, wishlist: false, hue: 200, tone: 'blue',  char: 'Y',
    category: 'collectibles', addedAt: '2026-01-10', hot: false,
    tags: ['max-factory', 'idol', 'pop-up-parade', '1/8'] },
  { id: 'f9', name: 'Rika Tachibana',line: 'Glass Wings',   maker: 'Alter', scale: '1/7',
    price: 234, status: 'soon',     release: '2027-01-20', payDays: 60, paid: 0,   wishlist: true,  hue: 195, tone: 'blue',  char: 'T',
    category: 'figures', addedAt: '2026-05-19', hot: true,
    tags: ['alter', 'fantasy', 'fairy', 'wings', 'limited-edition', '1/7'] },
  { id: 'f10',name: 'Akari Tsukimi', line: 'Starlight Vow', maker: 'GSC', scale: '1/6',
    price: 289, status: 'soon',     release: '2026-12-15', payDays: 45, paid: 0,   wishlist: true,  hue: 45,  tone: 'gold',  char: 'A',
    category: 'figures', addedAt: '2026-05-17', hot: true,
    tags: ['good-smile', 'fantasy', 'idol', '1/6', 'limited-edition'] },
  { id: 'f11',name: 'Saki Yumemori', line: 'Lunar Lace',    maker: 'Kotobukiya', scale: '1/8',
    price: 137, status: 'preorder', release: '2026-08-30', payDays: 9,  paid: 41,  wishlist: false, hue: 270, tone: 'lilac', char: 'S',
    category: 'figures', addedAt: '2026-04-22', hot: false,
    tags: ['kotobukiya', 'bishoujo', 'lace', 'fantasy', '1/8'] },
  { id: 'f12',name: 'Aoi Kazehaya',  line: 'Wind Maiden',   maker: 'Alter', scale: '1/7',
    price: 201, status: 'preorder', release: '2026-09-15', payDays: 24, paid: 0,   wishlist: true,  hue: 215, tone: 'blue',  char: 'K',
    category: 'figures', addedAt: '2026-05-16', hot: false,
    tags: ['alter', 'school-life', 'shrine-maiden', 'wind', '1/7'] },
];

// Inline SVG category icons — kawaii minimal line art with rounded strokes
// to match the bottom-nav icon vocabulary.
const NYA_CAT_ICONS = {
  all: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <path d="M12 3 L 14 10 L 21 12 L 14 14 L 12 21 L 10 14 L 3 12 L 10 10 Z"/>
    </svg>
  ),
  figures: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="12" cy="6" r="3"/>
      <path d="M8 21 L 9 13 H 15 L 16 21"/>
      <path d="M7 21 H 17"/>
      <path d="M9 13 L 7 11"/><path d="M15 13 L 17 11"/>
    </svg>
  ),
  collectibles: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <rect x="3" y="9" width="18" height="11" rx="2"/>
      <path d="M3 13 H 21"/><path d="M12 9 V 20"/>
      <path d="M8 9 C 5 9, 5 5, 8 5 C 10 5, 12 7, 12 9 C 12 7, 14 5, 16 5 C 19 5, 19 9, 16 9"/>
    </svg>
  ),
  tcg: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <rect x="3" y="6" width="11" height="15" rx="2" transform="rotate(-8 8.5 13.5)"/>
      <rect x="10" y="4" width="11" height="15" rx="2" transform="rotate(8 15.5 11.5)"/>
      <path d="M15 9 L 17 11 L 19 9"/>
    </svg>
  ),
  plush: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <path d="M6 9 L 4 5 L 8 7"/>
      <path d="M18 9 L 20 5 L 16 7"/>
      <circle cx="12" cy="13" r="7"/>
      <circle cx="9.5" cy="12" r=".7" fill="currentColor"/>
      <circle cx="14.5" cy="12" r=".7" fill="currentColor"/>
      <path d="M10 15 Q 12 16.5, 14 15"/>
    </svg>
  ),
  prepaid: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <rect x="3" y="6" width="18" height="13" rx="2.5"/>
      <path d="M3 11 H 21"/>
      <path d="M6.5 15 H 10"/><path d="M12.5 15 H 14"/>
    </svg>
  ),
  games: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <path d="M6 9 H 18 a 4 4 0 0 1 4 4 V 16 a 2 2 0 0 1 -2 2 L 18 18 L 16 15 H 8 L 6 18 L 4 18 a 2 2 0 0 1 -2 -2 V 13 a 4 4 0 0 1 4 -4 Z"/>
      <path d="M6.5 13 H 9.5"/><path d="M8 11.5 V 14.5"/>
      <circle cx="15.5" cy="12.5" r=".9" fill="currentColor"/>
      <circle cx="17.5" cy="14" r=".9" fill="currentColor"/>
    </svg>
  ),
  food: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <circle cx="7" cy="12" r="3.5"/>
      <circle cx="12" cy="8" r="3.5"/>
      <circle cx="17" cy="12" r="3.5"/>
      <path d="M3 18 H 21"/>
    </svg>
  ),
  spring26: (s = 22) => (
    <svg width={s} height={s} viewBox="0 0 24 24" fill="none" stroke="currentColor"
         strokeWidth="1.7" strokeLinecap="round" strokeLinejoin="round">
      <path d="M12 4 C 14 6, 14 8, 12 9 C 10 8, 10 6, 12 4 Z"/>
      <path d="M20 12 C 18 14, 16 14, 15 12 C 16 10, 18 10, 20 12 Z"/>
      <path d="M12 20 C 10 18, 10 16, 12 15 C 14 16, 14 18, 12 20 Z"/>
      <path d="M4 12 C 6 10, 8 10, 9 12 C 8 14, 6 14, 4 12 Z"/>
      <circle cx="12" cy="12" r="1.6" fill="currentColor"/>
    </svg>
  ),
};

// Categories — top-level departments mirrored from nin-nin-game.com
const NYA_CATEGORIES = [
  { id: 'figures',      label: 'Figures' },
  { id: 'collectibles', label: 'Collectibles' },
  { id: 'tcg',          label: 'TCG / Cards' },
  { id: 'plush',        label: 'Plush' },
  { id: 'prepaid',      label: 'Prepaid' },
  { id: 'games',        label: 'Video games' },
  { id: 'food',         label: 'Food & Snacks' },
  { id: 'spring26',     label: 'Spring Sales 26' },
];

// Quick filter chips — match nin-nin-game.com homepage rails
const NYA_QUICK_FILTERS = [
  { id: 'just-added', label: 'just added',      filter: (f) => new Date(f.addedAt) >= new Date('2026-05-10') },
  { id: 'hot-pre',    label: 'hot pre-orders',  filter: (f) => f.hot && f.status === 'preorder' },
  { id: 'hot',        label: 'hot products',    filter: (f) => f.hot },
];

// Currencies — rate is multiplier from base EUR. Round step keeps prices "tidy".
const NYA_CURRENCIES = {
  eur: { symbol: '€', label: '€ евро',    rate: 1,     locale: 'de-DE', round: 1   },
  rub: { symbol: '₽', label: '₽ рубли',   rate: 100,   locale: 'ru-RU', round: 10  },
  usd: { symbol: '$', label: '$ доллары', rate: 1.08,  locale: 'en-US', round: 1   },
  jpy: { symbol: '¥', label: '¥ иены',    rate: 165,   locale: 'ja-JP', round: 50  },
};

// React context — App lifts currency state, every screen reads via useContext.
const CurrencyContext = React.createContext('eur');

function nyaFormat(amount, currency = 'eur') {
  if (amount == null || isNaN(amount) || amount === 0) {
    return '—';
  }
  const c = NYA_CURRENCIES[currency] || NYA_CURRENCIES.eur;
  const v = Math.round(amount * c.rate / c.round) * c.round;
  const num = new Intl.NumberFormat(c.locale, { maximumFractionDigits: 0 }).format(v);
  // Symbol-front for €/$, symbol-back for ₽/¥ to match common conventions
  return currency === 'eur' || currency === 'usd'
    ? `${c.symbol}${num}`
    : `${num} ${c.symbol}`;
}

// Hook — pulls current currency from context and returns a curried formatter
function useFormat() {
  const cur = React.useContext(CurrencyContext);
  return React.useCallback(n => nyaFormat(n, cur), [cur]);
}

const RU_MONTHS = ['янв','фев','мар','апр','май','июн','июл','авг','сен','окт','ноя','дек'];
const RU_MONTHS_FULL = ['январь','февраль','март','апрель','май','июнь','июль','август','сентябрь','октябрь','ноябрь','декабрь'];

function nyaFormatDate(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d.getTime()) || d.getFullYear() <= 1970) return '—';
  return `${d.getDate()} ${RU_MONTHS[d.getMonth()]} ${String(d.getFullYear()).slice(2)}`;
}

function nyaFormatMonth(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  if (isNaN(d.getTime()) || d.getFullYear() <= 1970) return '—';
  return `${RU_MONTHS_FULL[d.getMonth()]} ${d.getFullYear()}`;
}

// Russian plural — picks form based on last digit (with 11-14 exception).
// Pass forms in [one, few, many] order: e.g. ['день','дня','дней'].
function ruPlural(n, forms) {
  const abs = Math.abs(n);
  const mod100 = abs % 100;
  const mod10 = abs % 10;
  if (mod100 >= 11 && mod100 <= 19) return forms[2];
  if (mod10 === 1) return forms[0];
  if (mod10 >= 2 && mod10 <= 4) return forms[1];
  return forms[2];
}

// ─── FiguresContext — App provides a live array (from /api/figures)
// when available, otherwise falls back to the mock NYA_FIGURES so the
// design still renders without a backend. ────────────────────────────────────
const FiguresContext = React.createContext(NYA_FIGURES);
function useFigures() { return React.useContext(FiguresContext); }

// ─── FigureArt — real photo when the figure carries one, otherwise the
// stylized SVG silhouette. The gallery is honored by view= ('back', 'box'
// pick later items so the detail screen's view-switcher behaves naturally).
function FigureArt({ figure, height = 180, view = 'front', style = {}, fit = 'contain' }) {
  const gallery = (figure && figure.image_urls) || (figure && figure.image_url ? [figure.image_url] : []);
  if (gallery && gallery.length) {
    // view can be a numeric gallery index OR a legacy mock view name.
    let idx;
    if (typeof view === 'number') {
      idx = Math.max(0, Math.min(view, gallery.length - 1));
    } else if (view === 'back') idx = Math.min(1, gallery.length - 1);
    else if (view === 'box') idx = gallery.length - 1;
    else idx = 0;
    return (
      <div style={{
        position: 'relative', width: '100%', height,
        borderRadius: 'var(--radius-sm)', overflow: 'hidden',
        background: 'linear-gradient(160deg, rgba(60,40,90,0.6), rgba(26,20,56,0.9))',
        boxShadow: 'inset 0 1px 0 rgba(255,255,255,.10), inset 0 -10px 30px rgba(0,0,0,.18)',
        ...style,
      }}>
        <img src={gallery[idx]} loading="lazy" draggable={false} alt={figure?.name || ''} style={{
          width: '100%', height: '100%', objectFit: fit, display: 'block',
          WebkitUserDrag: 'none', userDrag: 'none', WebkitTouchCallout: 'none',
          userSelect: 'none', pointerEvents: 'none',
        }}/>
      </div>
    );
  }
  return FigureArtPlaceholder({ figure, height, view, style });
}

function FigureArtPlaceholder({ figure, height = 180, view = 'front', style = {} }) {
  const h = figure.hue;
  const tones = {
    lilac: { bgA: `hsl(${h},55%,68%)`, bgB: `hsl(${h+10},45%,38%)`, body: `hsl(${h-10},70%,82%)`, hair: `hsl(${h+15},55%,55%)`, accent: '#ffd9eb' },
    pink:  { bgA: `hsl(${h},65%,72%)`, bgB: `hsl(${h-15},55%,42%)`, body: `hsl(${h-10},75%,88%)`, hair: `hsl(${h},65%,62%)`, accent: '#ffe6f0' },
    blue:  { bgA: `hsl(${h},55%,70%)`, bgB: `hsl(${h+15},50%,32%)`, body: `hsl(${h},45%,88%)`,  hair: `hsl(${h-5},55%,55%)`, accent: '#d9eeff' },
    rose:  { bgA: `hsl(${h},70%,75%)`, bgB: `hsl(${h-5},60%,40%)`,  body: `hsl(${h+5},70%,90%)`, hair: `hsl(${h-10},65%,60%)`, accent: '#ffd9d9' },
    gold:  { bgA: `hsl(${h},75%,72%)`, bgB: `hsl(280,50%,32%)`,     body: `hsl(${h},60%,88%)`,  hair: `hsl(${h-10},75%,55%)`, accent: '#fff2c4' },
  }[figure.tone];

  // View variants reuse the same SVG with a different viewBox / transform.
  // close — zoom to face. back — flip. box — full pulled out to show "box".
  const viewConf = {
    front: { vb: '0 0 100 130', preserve: 'xMidYMax meet', flip: false, box: false },
    close: { vb: '20 14 60 60',  preserve: 'xMidYMid meet', flip: false, box: false },
    back:  { vb: '0 0 100 130',  preserve: 'xMidYMax meet', flip: true,  box: false },
    box:   { vb: '-8 -8 116 146', preserve: 'xMidYMid meet', flip: false, box: true },
  }[view] || { vb: '0 0 100 130', preserve: 'xMidYMax meet', flip: false, box: false };

  const seed = figure.id;
  // tiny seeded sprinkles
  const sprinkles = React.useMemo(() => {
    let s = 0;
    for (let i = 0; i < seed.length; i++) s = (s * 31 + seed.charCodeAt(i)) >>> 0;
    const rng = () => { s = (s*1103515245+12345) & 0x7fffffff; return s / 0x7fffffff; };
    return Array.from({ length: 8 }, () => ({ x: rng() * 100, y: rng() * 100, r: 0.5 + rng() * 1.2 }));
  }, [seed]);

  return (
    <div style={{
      position: 'relative', width: '100%', height,
      borderRadius: 'var(--radius-sm)', overflow: 'hidden',
      background: `linear-gradient(160deg, ${tones.bgA} 0%, ${tones.bgB} 100%)`,
      boxShadow: 'inset 0 1px 0 rgba(255,255,255,.25), inset 0 -10px 30px rgba(0,0,0,.18)',
      ...style,
    }}>
      {/* sprinkles in bg */}
      <svg viewBox="0 0 100 100" preserveAspectRatio="none" width="100%" height="100%" style={{ position:'absolute', inset: 0 }}>
        {sprinkles.map((s,i) => <circle key={i} cx={s.x} cy={s.y} r={s.r} fill="#fff" opacity=".4"/>)}
      </svg>

      {/* figure silhouette — chibi-ish anime silhouette */}
      <svg viewBox={viewConf.vb} preserveAspectRatio={viewConf.preserve} width="100%" height="100%"
           style={{ position:'absolute', inset: 0 }}>
        {viewConf.box && (
          <>
            {/* "in-box" packaging frame */}
            <rect x="-6" y="-6" width="112" height="142" rx="4" fill="none"
                  stroke="rgba(255,255,255,.35)" strokeWidth="1.5"/>
            <rect x="-3" y="-3" width="106" height="136" rx="3" fill="none"
                  stroke="rgba(255,255,255,.15)" strokeWidth=".8"/>
          </>
        )}
        <g transform={viewConf.flip ? 'translate(100 0) scale(-1 1)' : ''}>
        {/* circular halo glow */}
        <circle cx="50" cy="55" r="35" fill={tones.accent} opacity=".25" filter="blur(8px)"/>

        {/* hair back */}
        <path d="M 28 38
                 C 28 24, 38 18, 50 18
                 C 62 18, 72 24, 72 38
                 L 72 78
                 C 70 82, 66 84, 62 84
                 L 38 84
                 C 34 84, 30 82, 28 78 Z"
              fill={tones.hair}/>
        {/* dress / body */}
        <path d="M 36 64
                 C 36 60, 42 56, 50 56
                 C 58 56, 64 60, 64 64
                 L 70 118
                 C 70 122, 65 124, 60 124
                 L 40 124
                 C 35 124, 30 122, 30 118 Z"
              fill={tones.body}/>
        {/* dress detail */}
        <path d="M 38 78 L 62 78" stroke={tones.hair} strokeWidth="1.2" opacity=".5"/>
        <path d="M 36 90 L 64 90" stroke={tones.hair} strokeWidth="1" opacity=".4"/>
        {/* ribbon */}
        <path d="M 42 64 L 50 60 L 58 64 L 56 70 L 50 67 L 44 70 Z" fill={tones.hair} opacity=".85"/>
        {/* head */}
        <ellipse cx="50" cy="42" rx="12" ry="14" fill={tones.body}/>
        {/* hair front */}
        <path d="M 38 38
                 C 38 28, 42 24, 50 24
                 C 58 24, 62 28, 62 38
                 C 60 36, 56 35, 52 36
                 C 50 32, 48 32, 46 36
                 C 42 35, 40 36, 38 38 Z"
              fill={tones.hair}/>
        {/* eyes */}
        <ellipse cx="45.5" cy="44" rx="1.6" ry="2.2" fill="#2a1a4a"/>
        <ellipse cx="54.5" cy="44" rx="1.6" ry="2.2" fill="#2a1a4a"/>
        <circle cx="46" cy="43.3" r=".6" fill="#fff"/>
        <circle cx="55" cy="43.3" r=".6" fill="#fff"/>
        {/* mouth */}
        <path d="M 49 48 q 1 1 2 0" stroke="#2a1a4a" strokeWidth=".8" fill="none" strokeLinecap="round"/>
        {/* cheeks */}
        <ellipse cx="44" cy="46.5" rx="1.5" ry=".8" fill="#ff9ecd" opacity=".7"/>
        <ellipse cx="56" cy="46.5" rx="1.5" ry=".8" fill="#ff9ecd" opacity=".7"/>

        {/* base / podium */}
        <ellipse cx="50" cy="125" rx="22" ry="3" fill="rgba(0,0,0,.25)"/>
        </g>
      </svg>
    </div>
  );
}

Object.assign(window, {
  NYA_FIGURES, NYA_CURRENCIES, NYA_CATEGORIES, NYA_QUICK_FILTERS, NYA_CAT_ICONS,
  CurrencyContext, useFormat, nyaFormat,
  nyaFormatDate, nyaFormatMonth, ruPlural,
  RU_MONTHS, RU_MONTHS_FULL, FigureArt, FigureArtPlaceholder,
  FiguresContext, useFigures,
});
