// mariusson — user-uploaded works (local-only)
//
// In a real deployment these go through mariusson's review queue and end
// up on a CDN. In this mock they live in localStorage as data-URL images,
// keyed under:
//
//   mariusson:user-works   array of work objects (same shape as the
//                           public-domain catalogue's `works`, plus a
//                           few extras: ownerId, listing, price,
//                           edition, protections, status)
//
// The catalogue loader (catalogue.jsx) merges these into the `works` array
// at runtime, so any user upload immediately shows up in the atlas, the
// wheel, and the global search.
//
// localStorage has a ~5MB cap. We compress new uploads to ~1400px max
// dimension on the way in, so a typical jpeg is 200–400 KB. That's roughly
// 12–25 uploads before we run out of headroom — fine for a demo.

(() => {
  const KEY = 'mariusson:user-works';
  const MAX_DIM = 1400;
  const JPEG_QUALITY = 0.86;

  function readWorks() {
    try {
      const raw = localStorage.getItem(KEY);
      return raw ? JSON.parse(raw) : [];
    } catch { return []; }
  }
  function writeWorks(works) {
    try { localStorage.setItem(KEY, JSON.stringify(works)); } catch (e) {
      throw new Error('Storage is full — clear some uploads or sign in fresh.');
    }
  }

  // Load a File via FileReader, then draw to a canvas and re-encode as JPEG
  // capped at MAX_DIM. Returns { dataUrl, width, height, aspect }.
  function compressImageFile(file) {
    return new Promise((resolve, reject) => {
      const reader = new FileReader();
      reader.onload = () => {
        const img = new Image();
        img.onload = () => {
          const scale = Math.min(1, MAX_DIM / Math.max(img.naturalWidth, img.naturalHeight));
          const w = Math.round(img.naturalWidth * scale);
          const h = Math.round(img.naturalHeight * scale);
          const canvas = document.createElement('canvas');
          canvas.width = w; canvas.height = h;
          const ctx = canvas.getContext('2d');
          // White background for any transparent PNGs — keeps JPEG output clean
          ctx.fillStyle = '#FAFAF7';
          ctx.fillRect(0, 0, w, h);
          ctx.drawImage(img, 0, 0, w, h);
          const dataUrl = canvas.toDataURL('image/jpeg', JPEG_QUALITY);
          resolve({ dataUrl, width: w, height: h, aspect: +(w / h).toFixed(4) });
        };
        img.onerror = () => reject(new Error('Could not decode image'));
        img.src = reader.result;
      };
      reader.onerror = () => reject(new Error('Could not read file'));
      reader.readAsDataURL(file);
    });
  }

  function makeWorkId() {
    return 'AN-U' + Math.random().toString(36).slice(2, 8).toUpperCase();
  }

  // ── public API ────────────────────────────────────────────────────

  // Add a new work. Owner is required (must be a signed-in account).
  // imageBlob is a File from <input type="file">. fields contains all
  // the user-entered metadata (title/year/region/style/method/theme,
  // listing mode, price, edition, protections).
  async function addWork(owner, imageFile, fields) {
    if (!owner || !owner.id) throw new Error('Sign in first');
    if (!imageFile) throw new Error('Pick an image');
    const { dataUrl, width, height, aspect } = await compressImageFile(imageFile);

    // `position` defines the order in the artist's portfolio carousel. New
    // works are appended (highest position so far + 1) so they show up at
    // the END by default. The artist can reorder via the Portfolio editor.
    const ownerWorks = readWorks().filter((w) => w.ownerId === owner.id);
    const maxPos = ownerWorks.reduce((m, w) => Math.max(m, w.position ?? 0), 0);

    const work = {
      id: makeWorkId(),
      artistId: owner.id,
      ownerId: owner.id,
      title: (fields.title || 'Untitled').trim(),
      year: Number(fields.year) || new Date().getFullYear(),
      region: fields.region || owner.region || 'France',
      style: fields.style || 'Modernist',
      method: fields.method || 'Oil',
      theme: fields.theme || 'Memory',
      image: dataUrl,
      imageWidth: width,
      imageHeight: height,
      aspect,
      listing: fields.listing || 'for-sale',
      price: fields.listing === 'view-only' ? null : (Number(fields.price) || null),
      edition: fields.edition || 'Unique',
      protections: fields.protections || {},
      status: 'review',     // 'review' → 'live' once approved (auto-approved here)
      createdAt: Date.now(),
      position: maxPos + 1,
      isUserUpload: true,
    };

    const all = readWorks();
    all.push(work);
    writeWorks(all);

    // Notify same-tab subscribers (storage event only fires across tabs).
    window.dispatchEvent(new Event('an-uploads-changed'));
    return work;
  }

  function listWorks() { return readWorks(); }

  function listWorksForOwner(ownerId) {
    return readWorks().filter((w) => w.ownerId === ownerId);
  }

  // Move a work up (-1) or down (+1) in the artist's portfolio order.
  // Swaps `position` with the adjacent neighbour; works are sorted by
  // position ascending throughout the UI.
  function moveWork(id, direction) {
    const all = readWorks();
    const target = all.find((w) => w.id === id);
    if (!target) throw new Error('Work not found');
    const peers = all
      .filter((w) => w.ownerId === target.ownerId)
      .sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
    const idx = peers.findIndex((w) => w.id === id);
    const swapIdx = idx + (direction < 0 ? -1 : 1);
    if (swapIdx < 0 || swapIdx >= peers.length) return target;
    const a = peers[idx], b = peers[swapIdx];
    const ai = all.findIndex((w) => w.id === a.id);
    const bi = all.findIndex((w) => w.id === b.id);
    const ap = a.position ?? 0, bp = b.position ?? 0;
    all[ai] = { ...a, position: bp };
    all[bi] = { ...b, position: ap };
    writeWorks(all);
    window.dispatchEvent(new Event('an-uploads-changed'));
    return all[ai];
  }

  // Drag-and-drop reorder — move `srcId` so it lands just before `destId`
  // (or at the end if destId is null). Recomputes all the owner's positions
  // in one shot using contiguous integers, so the order is unambiguous.
  function reorderWork(srcId, destId) {
    const all = readWorks();
    const src = all.find((w) => w.id === srcId);
    if (!src) throw new Error('Source work not found');
    const peers = all
      .filter((w) => w.ownerId === src.ownerId)
      .sort((a, b) => (a.position ?? 0) - (b.position ?? 0));

    const without = peers.filter((w) => w.id !== srcId);
    const destIdx = destId ? without.findIndex((w) => w.id === destId) : -1;
    const insertAt = destIdx < 0 ? without.length : destIdx;
    without.splice(insertAt, 0, src);

    // Re-stamp positions as 1, 2, 3, ... for that owner
    without.forEach((w, i) => {
      const ai = all.findIndex((x) => x.id === w.id);
      all[ai] = { ...all[ai], position: i + 1 };
    });
    writeWorks(all);
    window.dispatchEvent(new Event('an-uploads-changed'));
    return all;
  }

  function deleteWork(id) {
    const all = readWorks().filter((w) => w.id !== id);
    writeWorks(all);
    window.dispatchEvent(new Event('an-uploads-changed'));
  }

  // Patch a user-uploaded work (title, year, region, style, method, theme,
  // listing, price, edition, protections, status). Image bytes can't be
  // edited here — the user uploads a new work for that.
  function updateWork(id, patch) {
    const all = readWorks();
    const idx = all.findIndex((w) => w.id === id);
    if (idx < 0) throw new Error('Work not found');
    const allowed = ['title','year','region','style','method','theme','listing','price','edition','protections','status','position'];
    const safe = {};
    for (const k of allowed) if (k in (patch || {})) safe[k] = patch[k];
    all[idx] = { ...all[idx], ...safe };
    writeWorks(all);
    window.dispatchEvent(new Event('an-uploads-changed'));
    return all[idx];
  }

  // ── React hook ────────────────────────────────────────────────────

  function useUserWorks() {
    const [works, setWorks] = React.useState(() => readWorks());
    React.useEffect(() => {
      const refresh = () => setWorks(readWorks());
      window.addEventListener('an-uploads-changed', refresh);
      window.addEventListener('storage', (e) => {
        if (e.key === KEY || e.key === null) refresh();
      });
      return () => {
        window.removeEventListener('an-uploads-changed', refresh);
      };
    }, []);
    return works;
  }

  window.AN_UPLOADS = { addWork, listWorks, listWorksForOwner, deleteWork, updateWork, moveWork, reorderWork, KEY };
  window.useUserWorks = useUserWorks;
})();
