// mariusson — catalogue loader
//
// Loads data/catalogue.json (real public-domain artworks pulled from
// Wikimedia Commons via scripts/fetch_images.py). The JSON holds two arrays:
//   - artists: { id, name, region, born, died, bio }
//   - works:   { id, artistId, title, year, region, style, method, theme,
//                image, imageWidth, imageHeight, aspect, commonsFile }
//
// useCatalogue() returns null while loading and { artists, works } once ready.
// Each work is enriched with:
//   - artist:   the human-readable artist name (so existing code that filters
//               by `w.artist === artistName` keeps working)
//   - verified: deterministic ~60% true (kept from the placeholder model)
//   - price:    deterministic price tag, ~50% of works
//   - seed:     numeric seed used by background-palette logic in atlas.jsx

(() => {
  // Tiny seeded PRNG so verified/price are stable across reloads.
  function mulberry32(seed) {
    let a = seed >>> 0;
    return () => {
      a |= 0; a = a + 0x6D2B79F5 | 0;
      let t = Math.imul(a ^ a >>> 15, 1 | a);
      t = t + Math.imul(t ^ t >>> 7, 61 | t) ^ t;
      return ((t ^ t >>> 14) >>> 0) / 4294967296;
    };
  }

  function enrich(work, artistsById) {
    const seedNum = parseInt(String(work.id).replace(/\D/g, ''), 10) || 0;
    const r = mulberry32(seedNum + 1);
    const artist = artistsById[work.artistId];
    return {
      ...work,
      artist: artist ? artist.name : work.artistId,
      verified: r() > 0.4,
      price: r() > 0.45 ? Math.round(800 + r() * 24000) : null,
      seed: seedNum,
    };
  }

  // Cache the promise so multiple useCatalogue() calls share one fetch.
  let cataloguePromise = null;
  function loadCatalogue() {
    if (!cataloguePromise) {
      cataloguePromise = fetch('data/catalogue.json?v=20260430')
        .then((r) => {
          if (!r.ok) throw new Error('catalogue.json HTTP ' + r.status);
          return r.json();
        })
        .then((json) => {
          const artistsById = Object.fromEntries(json.artists.map((a) => [a.id, a]));
          const artistsByName = Object.fromEntries(json.artists.map((a) => [a.name, a]));
          const works = json.works.map((w) => enrich(w, artistsById));

          // Expose lookups for components that don't get the catalogue as a
          // prop (e.g. ArtistProfile reads bios via window.AN_ARTISTS_BY_NAME).
          window.AN_ARTISTS = json.artists;
          window.AN_ARTISTS_BY_ID = artistsById;
          window.AN_ARTISTS_BY_NAME = artistsByName;

          return { artists: json.artists, works };
        });
    }
    return cataloguePromise;
  }

  // Build a synthetic "artist" entry for a user upload, derived from the
  // owner account that's currently in localStorage. This lets the artist
  // profile drawer find a real bio for user-uploaded works.
  function syntheticArtist(account) {
    if (!account) return null;
    return {
      id: account.id,
      name: account.name || 'Anonymous',
      region: account.region || '—',
      born: null, died: null,
      bio: account.bio || 'A working artist on mariusson.',
      isUserArtist: true,
    };
  }

  function mergeUserUploads(base, userWorks) {
    if (!userWorks || !userWorks.length) return base;

    // Pick up the current account so user's uploads carry the right artist
    // name without needing a round-trip through the users list each time.
    const me = window.AN_AUTH ? window.AN_AUTH.currentAccount() : null;
    const usersById = {};
    if (me) usersById[me.id] = me;

    // Also pull anyone else who shows up as an owner in user-works (rare in
    // single-user demo, but cheap to do).
    try {
      const usersRaw = localStorage.getItem('mariusson:users');
      if (usersRaw) {
        for (const u of JSON.parse(usersRaw)) usersById[u.id] = u;
      }
    } catch {}

    // Sort uploads by their owner-defined position (ascending) so the
    // artist's chosen carousel order is respected everywhere — atlas,
    // search, the artist-profile cover-flow.
    const sortedUploads = [...userWorks].sort((a, b) => {
      if (a.ownerId !== b.ownerId) return 0;
      return (a.position ?? a.createdAt ?? 0) - (b.position ?? b.createdAt ?? 0);
    });
    const enrichedUploads = sortedUploads.map((w) => {
      const owner = usersById[w.ownerId];
      const artistName = owner?.name || 'Anonymous';
      const seedNum = parseInt(String(w.id).replace(/\D/g, ''), 36) || 0;
      const r = mulberry32(seedNum + 1);
      return {
        ...w,
        artist: artistName,
        verified: !!owner,
        seed: seedNum,
      };
    });

    // Synthetic artists: any owner not already in base.artists.
    const baseArtistIds = new Set(base.artists.map((a) => a.id));
    const newArtists = [];
    for (const id of new Set(userWorks.map((w) => w.ownerId))) {
      if (baseArtistIds.has(id)) continue;
      const u = usersById[id];
      if (u) newArtists.push(syntheticArtist(u));
    }

    const artists = [...base.artists, ...newArtists];
    // Index user-uploaded artists by name so artist-profile.jsx can look them up.
    const byName = window.AN_ARTISTS_BY_NAME || {};
    for (const a of newArtists) byName[a.name] = a;
    window.AN_ARTISTS_BY_NAME = byName;

    return { artists, works: [...base.works, ...enrichedUploads] };
  }

  function useCatalogue() {
    const [base, setBase] = React.useState(null);
    const [error, setError] = React.useState(null);
    const userWorks = window.useUserWorks ? window.useUserWorks() : [];

    React.useEffect(() => {
      let cancelled = false;
      loadCatalogue()
        .then((d) => { if (!cancelled) setBase(d); })
        .catch((e) => { if (!cancelled) setError(e); });
      return () => { cancelled = true; };
    }, []);

    const data = React.useMemo(
      () => base ? mergeUserUploads(base, userWorks) : null,
      [base, userWorks]
    );
    return { data, error };
  }

  function CatalogueSplash({ error }) {
    return (
      <div style={{
        position: 'absolute', inset: 0,
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        background: '#FAFAF7', color: '#0E0E0C',
        fontFamily: 'Cormorant Garamond, Georgia, serif',
        fontStyle: 'italic', fontSize: 28,
      }}>
        {/* Bauhaus splash mark */}
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 24 }}>
          <svg width="180" height="60" viewBox="0 0 180 60">
            <rect x="0" y="0" width="60" height="60" fill="#C8312B" />
            <circle cx="90" cy="30" r="30" fill="#E8B923" />
            <polygon points="120,60 150,0 180,60" fill="#1F4FA8" />
          </svg>
          <div style={{ textAlign: 'center' }}>mariusson</div>
          <div style={{
            fontFamily: 'JetBrains Mono, monospace',
            fontSize: 11, letterSpacing: '0.24em',
            color: error ? '#C8312B' : '#56564E',
            textTransform: 'uppercase', fontStyle: 'normal',
          }}>
            {error ? 'catalogue failed to load' : 'the atlas · loading'}
          </div>
        </div>
      </div>
    );
  }

  window.useCatalogue = useCatalogue;
  window.CatalogueSplash = CatalogueSplash;
})();
