(function() {
  'use strict';

  const browserApi = globalThis.browser || null;
  const chromeApi = globalThis.chrome || null;
  const VENDOO_BRAND_ICON = 'data:image/png;base64,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';

  function sendRuntimeMessage(message) {
    if (browserApi) return browserApi.runtime.sendMessage(message);
    return new Promise((resolve, reject) => chromeApi.runtime.sendMessage(message, response => {
      const error = chromeApi.runtime.lastError;
      if (error) reject(new Error(error.message)); else resolve(response);
    }));
  }
  function storageGet(keys) { return browserApi ? browserApi.storage.local.get(keys) : new Promise(resolve => chromeApi.storage.local.get(keys, resolve)); }
  function storageSet(values) { return browserApi ? browserApi.storage.local.set(values) : new Promise(resolve => chromeApi.storage.local.set(values, resolve)); }

  const STATE = {
    serverUrl: 'http://localhost:8124',
    connected: false,
    queue: [],
    published: [],
    selected: new Set(),
    batchDelay: 45,
    batchMode: 'draft',
    batchRunning: false,
    batchAbort: false,
    batchProgress: { current: 0, total: 0, currentId: null },
  };

  let panel, listEl;
  let serverCategories = null;

  async function loadServerCategories() {
    try {
      const data = await api('/api/categories/vinted');
      serverCategories = data;
      if (data.tree) window.VINTED_CATEGORIES = data.tree;
      if (data.flat) window.VINTED_CATEGORIES_FLAT = data.flat;
    } catch {}
  }

  async function serverMatchCategory(query) {
    if (!query) return [];
    try {
      return await api(`/api/categories/vinted/match?q=${encodeURIComponent(query)}`);
    } catch {
      return typeof matchCategory === 'function' ? matchCategory(query) : [];
    }
  }

  // --- API via Background Service Worker ---

  async function api(path, method, body) {
    const resp = await sendRuntimeMessage({ type: 'api', serverUrl: STATE.serverUrl, path, method: method || 'GET', body });
    if (!resp) throw new Error('Keine Antwort vom Extension-Background');
    if (!resp.ok) throw new Error(resp.data?.error || resp.error || `HTTP ${resp.status}`);
    return resp.data;
  }

  async function fetchImage(url) {
    const resp = await sendRuntimeMessage({ type: 'fetch-image', url });
    if (!resp || !resp.ok) throw new Error(resp?.error || 'Bild laden fehlgeschlagen');
    return resp;
  }


  const IMAGE_CACHE = new Map();

  function buildUploadUrl(filename) {
    if (!filename) return '';
    const safePath = String(filename).split('/').map(encodeURIComponent).join('/');
    return `${STATE.serverUrl.replace(/\/$/, '')}/uploads/${safePath}`;
  }

  function extensionPhotoMarkup(filename, className, altText) {
    if (!filename) return `<div class="${className} al-image-placeholder" aria-hidden="true"></div>`;
    return `<img class="${className} al-image-loading" data-vendoo-photo="${attr(filename)}" alt="${attr(altText || '')}">`;
  }

  async function resolveExtensionPhoto(filename) {
    if (!filename) return '';
    if (IMAGE_CACHE.has(filename)) return IMAGE_CACHE.get(filename);
    const promise = fetchImage(buildUploadUrl(filename))
      .then(result => result.dataUrl)
      .catch(error => {
        IMAGE_CACHE.delete(filename);
        throw error;
      });
    IMAGE_CACHE.set(filename, promise);
    return promise;
  }

  function hydrateExtensionImages(root) {
    if (!root) return;
    root.querySelectorAll('img[data-vendoo-photo]').forEach(async image => {
      const filename = image.dataset.vendooPhoto;
      try {
        image.src = await resolveExtensionPhoto(filename);
        image.classList.remove('al-image-loading', 'al-image-error');
        image.classList.add('al-image-ready');
      } catch {
        image.removeAttribute('src');
        image.classList.remove('al-image-loading');
        image.classList.add('al-image-error');
        image.alt = 'Produktbild konnte nicht geladen werden';
      }
    });
  }

  // --- Helpers ---

  function toast(msg, type) {
    let t = document.querySelector('.al-toast');
    if (!t) { t = document.createElement('div'); t.className = 'al-toast'; document.body.appendChild(t); }
    t.textContent = msg;
    t.className = 'al-toast ' + (type || '');
    requestAnimationFrame(() => t.classList.add('show'));
    setTimeout(() => t.classList.remove('show'), 3000);
  }

  function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }

  async function loadSettings() {
    try {
      const d = await storageGet(['serverUrl', 'batchDelay', 'batchMode']);
      if (d.serverUrl) STATE.serverUrl = d.serverUrl;
      if (d.batchDelay) STATE.batchDelay = parseInt(d.batchDelay) || 45;
      if (d.batchMode) STATE.batchMode = d.batchMode;
    } catch {}
  }

  async function checkConnection() {
    try {
      await api('/api/providers');
      STATE.connected = true;
      loadServerCategories();
    } catch {
      STATE.connected = false;
    }
    updateStatusBadge();
  }

  function detectDiagnosticBrowser() {
    const ua = navigator.userAgent || '';
    if (/Edg\//.test(ua)) return 'edge';
    if (/Firefox\//.test(ua)) return 'firefox';
    if (/Safari\//.test(ua) && !/Chrome\//.test(ua)) return 'safari';
    return 'chrome';
  }

  async function sendDiagnosticHeartbeat() {
    if (!STATE.connected) return;
    try {
      const stored = await storageGet(['vendooDiagnosticClientId']);
      const clientId = stored.vendooDiagnosticClientId || (globalThis.crypto?.randomUUID?.() || `vendoo-${Date.now()}-${Math.random().toString(16).slice(2)}`);
      if (!stored.vendooDiagnosticClientId) await storageSet({ vendooDiagnosticClientId: clientId });
      await api('/api/extensions/heartbeat', 'POST', {
        client_id: clientId,
        browser: detectDiagnosticBrowser(),
        version: '1.9.0',
        platform: 'vinted-content',
        server_url: STATE.serverUrl,
        capabilities: { autofill: true, photos: true, publishing_queue: true, diagnostics: true },
      });
    } catch {}
  }

  function updateStatusBadge() {
    const badge = panel?.querySelector('.al-hd-status');
    if (!badge) return;
    badge.textContent = STATE.connected ? 'Verbunden' : 'Offline';
    badge.className = 'al-hd-status ' + (STATE.connected ? 'live' : 'off');
  }

  // --- Data ---

  async function loadQueue() {
    if (!STATE.connected) return;
    try {
      const data = await api('/api/extension/queue?platform=vinted');
      STATE.queue = data.queue || [];
      STATE.published = data.published || [];
      const overviewCount = panel?.querySelector('#al-queue-overview-count');
      const overviewTitle = panel?.querySelector('#al-queue-overview-title');
      if (overviewCount) overviewCount.textContent = String(STATE.queue.length);
      if (overviewTitle) overviewTitle.textContent = STATE.queue.length ? 'Bereit zum Ausfüllen' : 'Alles erledigt';
      renderQueue();
      updateFooter();
    } catch (e) {
      toast('Laden fehlgeschlagen: ' + e.message, 'error');
    }
  }

  // --- UI ---

  function createPanel() {
    panel = document.createElement('div');
    panel.id = 'al-panel';
    panel.innerHTML = `
      <div class="al-hd">
        <img class="al-hd-brand-logo" src="${VENDOO_BRAND_ICON}" alt="" aria-hidden="true">
        <span class="al-hd-logo">Vendoo Assistant</span>
        <span class="al-hd-status off">...</span>
        <span class="al-hd-sep"></span>
        <button id="al-refresh" title="Aktualisieren">↻</button>
        <button id="al-minimize" title="Minimieren">↙</button>
        <button id="al-close" title="Schließen">×</button>
      </div>
      <div class="al-tabs">
        <button class="al-tab active" data-tab="queue">Warteschlange</button>
        <button class="al-tab" data-tab="done">Erledigt</button>
        <button class="al-tab" data-tab="settings">Einstellungen</button>
      </div>
      <div class="al-batch-bar" id="al-batch-bar">
        <input type="checkbox" class="al-cb" id="al-select-all" title="Alle auswählen">
        <label for="al-select-all" style="font-size:11px;color:#888;cursor:pointer">Alle</label>
        <span class="al-count" id="al-sel-count">0 ausgewählt</span>
      </div>
      <div class="al-body">
        <div class="al-view active" id="al-view-queue">
          <section class="al-queue-overview">
            <div><span>Vinted Workflow</span><strong id="al-queue-overview-title">Bereit zum Ausfüllen</strong><small>Wähle einen Artikel und übertrage die Daten kontrolliert.</small></div>
            <div class="al-queue-number"><b id="al-queue-overview-count">0</b><span>offen</span></div>
          </section>
          <ul class="al-list" id="al-queue-list"></ul>
        </div>
        <div class="al-view" id="al-view-done">
          <ul class="al-list" id="al-done-list"></ul>
        </div>
        <div class="al-view" id="al-view-settings">
          <div class="al-settings">
            <div class="al-setting">
              <div class="al-setting-label">Batch-Modus</div>
              <select class="al-select" id="al-batch-mode">
                <option value="draft" ${STATE.batchMode === 'draft' ? 'selected' : ''}>Als Entwurf speichern</option>
                <option value="publish" ${STATE.batchMode === 'publish' ? 'selected' : ''}>Direkt veröffentlichen</option>
              </select>
              <small class="al-setting-hint">„Nur ausfüllen“ ist bewusst eine Einzelaktion und speichert oder veröffentlicht nichts.</small>
            </div>
            <div class="al-setting">
              <div class="al-setting-label">Pause zwischen Artikeln (Sek.)</div>
              <input type="number" class="al-input" id="al-delay" min="10" max="300" value="${STATE.batchDelay}">
            </div>
            <div class="al-setting">
              <div class="al-setting-label">Server URL</div>
              <input type="text" class="al-input" id="al-server-url" value="${STATE.serverUrl}">
            </div>
            <div class="al-setting">
              <button class="al-btn al-btn-ghost al-btn-full" id="al-test-conn">Verbindung testen</button>
            </div>
            <div class="al-setting">
              <button class="al-btn al-btn-ghost al-btn-full" id="al-open-app">Vendoo App öffnen</button>
            </div>
          </div>
        </div>
        <div class="al-view" id="al-view-detail"></div>
        <div class="al-view" id="al-view-batch-progress"></div>
      </div>
      <div class="al-footer" id="al-footer">
        <div class="al-footer-row" id="al-footer-actions">
          <button class="al-btn al-btn-fill al-btn-full" id="al-start-batch" disabled>Artikel auswählen</button>
        </div>
      </div>
      <div class="al-resize-handle" id="al-resize-handle"></div>
    `;
    document.body.appendChild(panel);
    listEl = panel.querySelector('#al-queue-list');
    bindEvents();
    setupDrag();
    setupResize();
  }

  function bindEvents() {
    panel.querySelectorAll('.al-tab').forEach(tab =>
      tab.addEventListener('click', () => switchTab(tab.dataset.tab))
    );
    panel.querySelector('#al-refresh').addEventListener('click', () => {
      checkConnection().then(() => { if (STATE.connected) loadQueue(); });
    });
    panel.querySelector('#al-minimize').addEventListener('click', minimize);
    panel.querySelector('#al-close').addEventListener('click', close);
    panel.querySelector('#al-select-all').addEventListener('change', e => {
      if (e.target.checked) STATE.queue.forEach(l => STATE.selected.add(l.id));
      else STATE.selected.clear();
      renderQueue(); updateFooter();
    });
    panel.querySelector('#al-start-batch').addEventListener('click', () => {
      if (STATE.batchRunning) { STATE.batchAbort = true; return; }
      startBatch();
    });
    panel.querySelector('#al-delay').addEventListener('change', e => {
      STATE.batchDelay = Math.max(10, Math.min(300, parseInt(e.target.value) || 45));
      storageSet({ batchDelay: String(STATE.batchDelay) });
    });
    panel.querySelector('#al-batch-mode').addEventListener('change', e => {
      STATE.batchMode = e.target.value;
      storageSet({ batchMode: STATE.batchMode });
      updateFooter();
    });
    panel.querySelector('#al-test-conn').addEventListener('click', async () => {
      STATE.serverUrl = panel.querySelector('#al-server-url').value.replace(/\/$/, '');
      await storageSet({ serverUrl: STATE.serverUrl });
      await checkConnection();
      toast(STATE.connected ? 'Verbunden!' : 'Server nicht erreichbar', STATE.connected ? 'success' : 'error');
      if (STATE.connected) loadQueue();
    });
    panel.querySelector('#al-open-app').addEventListener('click', () => {
      window.open(STATE.serverUrl, '_blank');
    });
  }

  function setupDrag() {
    const hd = panel.querySelector('.al-hd');
    let dragging = false, ox = 0, oy = 0;
    hd.addEventListener('mousedown', e => {
      if (e.target.tagName === 'BUTTON') return;
      dragging = true;
      const r = panel.getBoundingClientRect();
      ox = e.clientX - r.left; oy = e.clientY - r.top;
      e.preventDefault();
    });
    document.addEventListener('mousemove', e => {
      if (!dragging) return;
      panel.style.right = 'auto';
      panel.style.top = (e.clientY - oy) + 'px';
      panel.style.left = (e.clientX - ox) + 'px';
    });
    document.addEventListener('mouseup', () => { dragging = false; });
  }

  function setupResize() {
    const handle = panel.querySelector('#al-resize-handle');
    let resizing = false, startW, startH, startX, startY;
    handle.addEventListener('mousedown', e => {
      resizing = true;
      startW = panel.offsetWidth;
      startH = panel.offsetHeight;
      startX = e.clientX;
      startY = e.clientY;
      e.preventDefault(); e.stopPropagation();
    });
    document.addEventListener('mousemove', e => {
      if (!resizing) return;
      panel.style.width = Math.max(300, startW + (e.clientX - startX)) + 'px';
      panel.style.height = Math.max(350, startH + (e.clientY - startY)) + 'px';
    });
    document.addEventListener('mouseup', () => { resizing = false; });
  }

  function switchTab(tab) {
    panel.querySelectorAll('.al-tab').forEach(t => t.classList.toggle('active', t.dataset.tab === tab));
    panel.querySelectorAll('.al-view').forEach(v => v.classList.remove('active'));
    panel.querySelector(`#al-view-${tab}`).classList.add('active');
    panel.querySelector('#al-batch-bar').style.display = tab === 'queue' ? '' : 'none';
    panel.querySelector('#al-footer').style.display = (tab === 'queue' || tab === 'batch-progress') ? '' : 'none';
    if (tab === 'done') renderDone();
  }

  function switchToView(name) {
    panel.querySelectorAll('.al-view').forEach(v => v.classList.remove('active'));
    panel.querySelector(`#al-view-${name}`).classList.add('active');
    panel.querySelectorAll('.al-tab').forEach(t => t.classList.remove('active'));
    panel.querySelector('#al-batch-bar').style.display = name === 'queue' ? '' : 'none';
    panel.querySelector('#al-footer').style.display = name === 'batch-progress' ? '' : 'none';
  }

  function minimize() {
    panel.remove();
    const fab = document.createElement('button');
    fab.className = 'al-fab'; fab.id = 'al-fab';
    fab.innerHTML = `<img src="${VENDOO_BRAND_ICON}" alt="">`;  fab.title = 'Vendoo Assistant öffnen';
    document.body.appendChild(fab);
    fab.addEventListener('click', () => { fab.remove(); createPanel(); init(); });
  }

  function close() { panel.remove(); panel = null; }

  // --- Render ---

  function renderQueue() {
    if (!listEl) return;
    if (!STATE.queue.length) {
      listEl.innerHTML = '<li class="al-empty"><span class="al-empty-icon">✓</span><strong>Warteschlange erledigt</strong><small>Neue Vinted-Listings erscheinen automatisch hier.</small></li>';
      return;
    }
    listEl.innerHTML = STATE.queue.map(l => {
      const sel = STATE.selected.has(l.id);
      const photo = l.photos?.[0] || '';
      const cls = ['al-item'];
      if (sel) cls.push('selected');
      if (STATE.batchProgress.currentId === l.id) cls.push('processing');
      const statusHtml = STATE.batchProgress.currentId === l.id ? '<span class="al-item-status running">Läuft</span>' : '<span class="al-item-status ready">Bereit</span>';
      return `
        <li class="${cls.join(' ')}" data-id="${l.id}">
          <div class="al-item-select"><input type="checkbox" class="al-cb al-item-cb" data-id="${l.id}" ${sel ? 'checked' : ''} aria-label="${attr(l.title || 'Artikel')} auswählen"></div>
          ${extensionPhotoMarkup(photo, 'al-item-img', l.title || 'Produktbild')}
          <div class="al-item-info">
            <div class="al-item-topline">${statusHtml}<span>Vinted</span></div>
            <div class="al-item-title">${esc(l.title || 'Ohne Titel')}</div>
            <div class="al-item-meta">${esc(l.brand || 'Ohne Marke')}${l.size ? ' · ' + esc(l.size) : ''}${l.condition ? ' · ' + esc(l.condition) : ''}</div>
            <div class="al-item-sku">${esc(l.sku || `VD-${String(l.id).padStart(4, '0')}`)}</div>
          </div>
          <div class="al-item-side">${l.price ? `<strong>${Number(l.price).toFixed(2).replace('.', ',')} €</strong>` : '<strong>Preis fehlt</strong>'}<button class="al-item-open" type="button" data-id="${l.id}" title="Details öffnen">›</button></div>
          <div class="al-item-actions">
            <button class="al-quick-fill" type="button" data-id="${l.id}"><span>↗</span> Daten</button>
            <button class="al-quick-fill al-quick-fill-all" type="button" data-id="${l.id}">Bilder</button>
            <button class="al-quick-detail" type="button" data-id="${l.id}">Prüfen</button>
          </div>
        </li>`;
    }).join('');
    hydrateExtensionImages(listEl);

    listEl.querySelectorAll('.al-item-cb').forEach(cb =>
      cb.addEventListener('change', e => {
        e.stopPropagation();
        const id = +e.target.dataset.id;
        if (e.target.checked) STATE.selected.add(id); else STATE.selected.delete(id);
        renderQueue(); updateFooter();
      })
    );
    listEl.querySelectorAll('.al-quick-fill').forEach(button => button.addEventListener('click', async e => {
      e.stopPropagation();
      const listing = STATE.queue.find(l => l.id === +button.dataset.id);
      if (!listing) return;
      const includePhotos = button.classList.contains('al-quick-fill-all');
      await fillListingData(listing, { includePhotos });
    }));
    listEl.querySelectorAll('.al-quick-detail,.al-item-open').forEach(button => button.addEventListener('click', e => {
      e.stopPropagation();
      showDetail(+button.dataset.id);
    }));
    listEl.querySelectorAll('.al-item').forEach(item =>
      item.addEventListener('click', e => {
        if (e.target.closest('button,input')) return;
        showDetail(+item.dataset.id);
      })
    );
    panel.querySelector('#al-select-all').checked = STATE.selected.size === STATE.queue.length && STATE.queue.length > 0;
  }

  function renderDone() {
    const dl = panel.querySelector('#al-done-list');
    if (!STATE.published.length) {
      dl.innerHTML = '<li class="al-empty"><span class="al-empty-icon">&#128230;</span>Noch keine Artikel veröffentlicht.</li>';
      return;
    }
    dl.innerHTML = STATE.published.map(l => {
      const photo = l.photos?.[0] || '';
      return `
        <li class="al-item done">
          ${extensionPhotoMarkup(photo, 'al-item-img', l.title || 'Produktbild')}
          <div class="al-item-info">
            <div class="al-item-title">${esc(l.title || 'Ohne Titel')}</div>
            <div class="al-item-meta">${esc(l.brand || '')}${l.price ? ' · ' + Number(l.price).toFixed(2) + ' €' : ''}</div>
          </div>
          <span class="al-item-status done">Erledigt</span>
        </li>`;
    }).join('');
    hydrateExtensionImages(dl);
  }

  function updateFooter() {
    const count = STATE.selected.size;
    panel.querySelector('#al-sel-count').textContent = `${count} ausgewählt`;
    const actions = panel.querySelector('#al-footer-actions');
    if (STATE.batchRunning) {
      actions.innerHTML = '<button class="al-btn al-btn-danger al-btn-full" id="al-start-batch">Batch abbrechen</button>';
      actions.querySelector('#al-start-batch').addEventListener('click', () => { STATE.batchAbort = true; });
      return;
    }
    if (count === 1) {
      const id = [...STATE.selected][0];
      actions.innerHTML = `
        <button class="al-btn al-btn-fill" id="al-selection-fill">Nur Daten</button>
        <button class="al-btn al-btn-ghost" id="al-selection-fill-all">Daten + Bilder</button>
        <button class="al-btn al-btn-ghost" id="al-selection-detail">Prüfen</button>
        <button class="al-btn al-btn-primary" id="al-batch-draft">Entwurf</button>
        <button class="al-btn al-btn-fill" id="al-batch-publish">Live</button>`;
      actions.querySelector('#al-selection-fill').addEventListener('click', async () => {
        const listing = STATE.queue.find(l => l.id === id);
        if (listing) await fillListingData(listing, { includePhotos: false });
      });
      actions.querySelector('#al-selection-fill-all').addEventListener('click', async () => {
        const listing = STATE.queue.find(l => l.id === id);
        if (listing) await fillListingData(listing, { includePhotos: true });
      });
      actions.querySelector('#al-selection-detail').addEventListener('click', () => showDetail(id));
      actions.querySelector('#al-batch-draft').addEventListener('click', () => { STATE.batchMode = 'draft'; startBatch(); });
      actions.querySelector('#al-batch-publish').addEventListener('click', () => { STATE.batchMode = 'publish'; startBatch(); });
    } else if (count > 1) {
      actions.innerHTML = `
        <div class="al-footer-note"><strong>${count} Artikel ausgewählt</strong><span>Mehrfachauswahl unterstützt Batch-Entwurf oder direkte Veröffentlichung.</span></div>
        <button class="al-btn al-btn-primary" id="al-batch-draft">Entwürfe</button>
        <button class="al-btn al-btn-fill" id="al-batch-publish">Veröffentlichen</button>`;
      actions.querySelector('#al-batch-draft').addEventListener('click', () => { STATE.batchMode = 'draft'; startBatch(); });
      actions.querySelector('#al-batch-publish').addEventListener('click', () => { STATE.batchMode = 'publish'; startBatch(); });
    } else {
      actions.innerHTML = '<div class="al-footer-empty"><span>Aktionen sichtbar, sobald du ein Listing auswählst</span><small>Direkt in jeder Karte: Daten, Bilder und Prüfen.</small></div>';
    }
  }

  // --- Detail ---

  function showDetail(id) {
    const listing = STATE.queue.find(l => l.id === id) || STATE.published.find(l => l.id === id);
    if (!listing) return;
    const view = panel.querySelector('#al-view-detail');
    const photos = listing.photos || [];
    view.innerHTML = `
      <div class="al-detail">
        <button class="al-detail-back">&larr; Zurück</button>

        <div class="al-detail-hero">
          ${extensionPhotoMarkup(photos[0] || '', 'al-detail-main-photo', `${listing.title || 'Produkt'} · Cover`)}
          <div class="al-detail-summary">
            <span class="al-detail-ready">Bereit</span>
            <h2>${esc(listing.title || 'Ohne Titel')}</h2>
            <strong>${listing.price ? Number(listing.price).toFixed(2).replace('.', ',') + ' €' : 'Preis fehlt'}</strong>
            <dl><dt>Kategorie</dt><dd>${esc(listing.category || 'Nicht gesetzt')}</dd><dt>Marke</dt><dd>${esc(listing.brand || '–')}</dd><dt>Größe</dt><dd>${esc(listing.size || '–')}</dd><dt>Zustand</dt><dd>${esc(listing.condition || '–')}</dd></dl>
          </div>
        </div>
        <div class="al-detail-photos">${photos.map((photo, index) => extensionPhotoMarkup(photo, 'al-detail-photo', `${listing.title || 'Produkt'} · Bild ${index + 1}`)).join('')}</div>

        <div class="al-publish-flow">
          <h3>Veröffentlichen auf Vinted</h3>
          <div class="al-flow-grid">
            <ol><li class="done"><b>1</b><span><strong>Daten prüfen</strong><small>Titel, Preis, Kategorie, Größe</small></span><em>✓</em></li><li class="done"><b>2</b><span><strong>Bilder vorbereiten</strong><small>${photos.length}/${photos.length || 0} Bilder verfügbar</small></span><em>✓</em></li><li class="done"><b>3</b><span><strong>Beschreibung übernehmen</strong><small>Beschreibung und Attribute</small></span><em>✓</em></li><li class="active"><b>4</b><span><strong>Auto-Fill auf Vinted</strong><small>Formular automatisch ausfüllen</small></span><em>○</em></li><li><b>5</b><span><strong>Veröffentlichung</strong><small>Listing abschließen</small></span><em>○</em></li></ol>
            <div class="al-autofill-card"><span>Auto-Fill · Vinted</span><p>Vendoo übernimmt alle vorhandenen Listing-Daten.</p><ul><li>✓ Titel</li><li>✓ Preis</li><li>✓ Kategorie</li><li>✓ Größe &amp; Marke</li><li>✓ Beschreibung</li><li>✓ Bilder</li></ul><div><strong>✓ Bereit zum Übertragen</strong><small>Alle Pflichtdaten werden vorab geprüft.</small></div></div>
          </div>
        </div>

        <details class="al-edit-details"><summary>Listing-Daten prüfen &amp; bearbeiten</summary>
        <div class="al-field">
          <div class="al-field-label">Titel</div>
          <input type="text" id="al-d-title" value="${attr(listing.title || '')}">
        </div>
        <div class="al-field">
          <div class="al-field-label">Beschreibung</div>
          <textarea id="al-d-desc" rows="4">${esc(listing.description || '')}</textarea>
        </div>
        <div class="al-meta-row">
          <div class="al-field">
            <div class="al-field-label">Preis</div>
            <input type="text" id="al-d-price" value="${attr(listing.price || '')}">
          </div>
          <div class="al-field">
            <div class="al-field-label">Zustand</div>
            <input type="text" id="al-d-condition" value="${attr(listing.condition || '')}">
          </div>
        </div>
        <div class="al-meta-row">
          <div class="al-field">
            <div class="al-field-label">Marke</div>
            <input type="text" id="al-d-brand" value="${attr(listing.brand || '')}">
          </div>
          <div class="al-field">
            <div class="al-field-label">Größe</div>
            <input type="text" id="al-d-size" value="${attr(listing.size || '')}">
          </div>
        </div>
        <div class="al-field">
          <div class="al-field-label">Kategorie (Vinted)</div>
          <div class="al-cat-wrap" id="al-cat-wrap">
            <input type="text" class="al-cat-input" id="al-d-category" placeholder="Kategorie suchen..." value="${attr(listing.category || '')}" autocomplete="off">
            <div class="al-cat-dropdown" id="al-cat-dropdown"></div>
            <div id="al-cat-selected-display"></div>
          </div>
        </div>
        <div class="al-meta-row">
          <div class="al-field">
            <div class="al-field-label">Farbe</div>
            <input type="text" id="al-d-color" value="${attr(listing.color || '')}">
          </div>
          <div class="al-field">
            <div class="al-field-label">AI-Kategorie (Original)</div>
            <input type="text" class="al-field-readonly" id="al-d-ai-category" value="${attr(listing.category || '')}" readonly style="opacity:0.6">
          </div>
        </div>
        <div class="al-field">
          <div class="al-field-label">Tags</div>
          <input type="text" id="al-d-tags" value="${attr((listing.tags || []).join(' '))}">
        </div>

        </details>

        <div class="al-detail-section-label">ÜBERTRAGEN – OHNE SPEICHERN</div>
        <div class="al-safe-actions">
          <button class="al-btn al-btn-fill al-btn-full" id="al-d-fields"><span class="al-btn-icon">↗</span> Nur Daten ausfüllen</button>
          <button class="al-btn al-btn-ghost al-btn-full" id="al-d-fill-all"><span class="al-btn-icon">▧</span> Daten + Bilder ausfüllen</button>
          <p>Diese Aktionen füllen das Vinted-Formular nur aus. Es wird weder ein Entwurf gespeichert noch veröffentlicht.</p>
        </div>

        <details class="al-final-actions">
          <summary>Entwurf speichern oder veröffentlichen</summary>
          <div class="al-final-grid">
            <button class="al-btn al-btn-primary" id="al-d-draft">Als Entwurf</button>
            <button class="al-btn al-btn-fill" id="al-d-publish">Veröffentlichen</button>
            <button class="al-btn al-btn-ghost" id="al-d-all-draft">Alles + Entwurf</button>
            <button class="al-btn al-btn-ghost" id="al-d-all-publish">Alles + Veröffentlichen</button>
          </div>
        </details>
        <button class="al-btn al-btn-ghost al-btn-full" id="al-d-copy">Listing-Daten kopieren</button>
      </div>
    `;

    const v = view;
    hydrateExtensionImages(view);
    v.querySelector('.al-detail-back').addEventListener('click', () => switchTab('queue'));

    // Category picker
    initCategoryPicker(v, listing.category || '');

    v.querySelector('#al-d-fields').addEventListener('click', async () => {
      await fillListingData({ ...listing, ...readDetailFields() }, { includePhotos: false });
    });

    v.querySelector('#al-d-fill-all').addEventListener('click', async () => {
      await fillListingData({ ...listing, ...readDetailFields(), photos: listing.photos || [] }, { includePhotos: true });
    });

    v.querySelector('#al-d-draft').addEventListener('click', async () => {
      clickVintedButton('draft');
      await markStatus(id, 'draft');
      toast('Als Entwurf gespeichert', 'success');
    });

    v.querySelector('#al-d-publish').addEventListener('click', async () => {
      clickVintedButton('publish');
      await markStatus(id, 'published');
      toast('Veröffentlicht!', 'success');
    });

    v.querySelector('#al-d-all-draft').addEventListener('click', async () => {
      await doFullListing(listing, 'draft');
      await markStatus(id, 'draft');
    });

    v.querySelector('#al-d-all-publish').addEventListener('click', async () => {
      await doFullListing(listing, 'publish');
      await markStatus(id, 'published');
    });

    v.querySelector('#al-d-copy').addEventListener('click', () => {
      const f = readDetailFields();
      navigator.clipboard.writeText(`${f.title}\n\n${f.description}\n\nPreis: ${f.price}\nKategorie: ${f.category}\nTags: ${f.tags}`);
      toast('Kopiert!', 'success');
    });

    switchToView('detail');
  }

  function readDetailFields() {
    return {
      title: panel.querySelector('#al-d-title').value,
      description: panel.querySelector('#al-d-desc').value,
      price: panel.querySelector('#al-d-price').value,
      condition: panel.querySelector('#al-d-condition').value,
      brand: panel.querySelector('#al-d-brand').value,
      size: panel.querySelector('#al-d-size').value,
      category: panel.querySelector('#al-d-category').value,
      color: panel.querySelector('#al-d-color').value,
      tags: panel.querySelector('#al-d-tags').value,
    };
  }

  // --- Sicheres Ausfüllen ohne Speichern oder Veröffentlichen ---

  async function fillListingData(listing, options = {}) {
    const includePhotos = options.includePhotos === true;
    const fields = {
      title: listing.title || '',
      description: listing.description || '',
      price: listing.price ? String(listing.price) : '',
      condition: listing.condition || '',
      brand: listing.brand || '',
      size: listing.size || '',
      category: listing.category || '',
      color: listing.color || '',
      tags: Array.isArray(listing.tags) ? listing.tags.join(' ') : (listing.tags || ''),
    };

    toast(includePhotos ? 'Daten und Bilder werden vorbereitet …' : 'Daten werden in Vinted eingetragen …');
    if (includePhotos && Array.isArray(listing.photos) && listing.photos.length) {
      await uploadPhotos(listing.photos);
      await sleep(700);
    }

    fillVintedForm(fields);
    await fillVintedChoiceFields(fields);
    if (fields.category) await selectCategory(fields.category);

    toast(includePhotos
      ? 'Daten und Bilder ausgefüllt – noch nicht gespeichert.'
      : 'Daten ausgefüllt – noch nicht gespeichert.', 'success');
  }

  async function fillVintedChoiceFields(fields) {
    const jobs = [
      [['Marke', 'Brand'], fields.brand],
      [['Größe', 'Size'], fields.size],
      [['Zustand', 'Condition'], fields.condition],
      [['Farbe', 'Color'], fields.color],
    ];
    for (const [labels, value] of jobs) {
      if (!value) continue;
      await chooseVintedOption(labels, value);
    }
  }

  async function chooseVintedOption(labels, value) {
    const normalized = normalizedFieldText(value);
    if (!normalized) return false;
    const wantedLabels = labels.map(normalizedFieldText);
    let trigger = null;
    let triggerIsExplicitlyAssociated = false;
    const labelNodes = [...document.querySelectorAll('label')]
      .filter(label => !isExtensionElement(label))
      .sort((a, b) => normalizedFieldText(a.textContent).length - normalizedFieldText(b.textContent).length);
    for (const label of labelNodes) {
      const text = normalizedFieldText(label.textContent);
      if (!wantedLabels.some(item => text === item || text.startsWith(`${item} `) || text.startsWith(`${item}*`))) continue;
      trigger = getAssociatedControl(label, 'button,[role="button"],select,input');
      if (trigger) {
        triggerIsExplicitlyAssociated = Boolean(
          (label.htmlFor && trigger.id === label.htmlFor)
          || label.contains(trigger)
          || trigger.getAttribute?.('aria-labelledby')?.split(/\s+/).includes(label.id)
          || label.nextElementSibling?.contains?.(trigger)
          || label.nextElementSibling === trigger
        );
        break;
      }
    }
    if (!trigger) {
      for (const el of document.querySelectorAll('button,[role="button"]')) {
        if (isExtensionElement(el)) continue;
        const text = normalizedFieldText(el.textContent);
        if (wantedLabels.some(item => text === item || text.startsWith(`${item} `))) { trigger = el; break; }
      }
    }
    if (!trigger || isLikelyTitleField(trigger)) return false;
    if (trigger.tagName === 'INPUT') {
      const role = normalizedFieldText(trigger.getAttribute('role'));
      const type = normalizedFieldText(trigger.type || 'text');
      if (!triggerIsExplicitlyAssociated && role !== 'combobox') return false;
      if (!['text', 'search', 'button'].includes(type) && role !== 'combobox') return false;
      setNativeValue(trigger, value);
      return true;
    }
    if (trigger.tagName === 'SELECT') {
      const option = [...trigger.options].find(o => o.textContent.trim().toLowerCase().includes(normalized));
      if (option) { trigger.value = option.value; trigger.dispatchEvent(new Event('change', { bubbles: true })); return true; }
      return false;
    }
    trigger.click();
    await sleep(350);
    for (const option of document.querySelectorAll('[role="option"],li,button,[role="button"]')) {
      if (option.closest('#al-panel')) continue;
      const text = option.textContent.trim().toLowerCase();
      if (text && (text === normalized || text.includes(normalized) || normalized.includes(text))) {
        option.click();
        await sleep(180);
        return true;
      }
    }
    return false;
  }

  // --- Full listing (photos + fields + category + submit) ---

  async function doFullListing(listing, mode) {
    const steps = panel.querySelector('#al-d-fields')?.parentElement;
    if (!steps) return;

    toast('Starte Komplett-Eintrag...', 'success');

    // 1–3) Bilder, Felder und Kategorie ausfüllen
    await fillListingData(listing, { includePhotos: true });
    await sleep(700);

    // 4) Submit
    toast('Abschluss: ' + (mode === 'draft' ? 'Entwurf speichern …' : 'Veröffentlichen …'));
    await sleep(500);
    clickVintedButton(mode);
    toast(mode === 'draft' ? 'Als Entwurf gespeichert!' : 'Veröffentlicht!', 'success');
  }

  // --- Photo Upload ---

  async function uploadPhotos(photoFilenames) {
    if (!photoFilenames.length) return { ok: false, count: 0 };

    const dropzone = findPhotoDropzone();
    const fileInput = findPhotoFileInput();

    if (!dropzone && !fileInput) {
      toast('Foto-Upload Bereich nicht gefunden. Bitte lade Fotos manuell hoch.', 'error');
      return { ok: false, count: 0 };
    }

    const files = [];
    for (const filename of photoFilenames) {
      try {
        const url = buildUploadUrl(filename);
        const imgData = await fetchImage(url);
        const byteString = atob(imgData.dataUrl.split(',')[1]);
        const ab = new ArrayBuffer(byteString.length);
        const ia = new Uint8Array(ab);
        for (let i = 0; i < byteString.length; i++) ia[i] = byteString.charCodeAt(i);
        const ext = filename.split('.').pop().toLowerCase();
        const mime = imgData.mime || ({ jpg: 'image/jpeg', jpeg: 'image/jpeg', png: 'image/png', webp: 'image/webp', gif: 'image/gif' }[ext] || 'image/jpeg');
        files.push(new File([ab], filename, { type: mime }));
      } catch (err) {
        console.warn('Vendoo: Foto laden fehlgeschlagen:', filename, err);
      }
    }

    if (!files.length) {
      toast('Keine Fotos geladen', 'error');
      return { ok: false, count: 0 };
    }

    if (fileInput) {
      try {
        const dt = new DataTransfer();
        files.forEach(f => dt.items.add(f));
        fileInput.files = dt.files;
        fileInput.dispatchEvent(new Event('change', { bubbles: true }));
        toast(`${files.length} Fotos hochgeladen`, 'success');
        return { ok: true, count: files.length };
      } catch (err) {
        console.warn('Vendoo: FileInput-Methode fehlgeschlagen, versuche Drop:', err);
      }
    }

    if (dropzone) {
      try {
        const dt = new DataTransfer();
        files.forEach(f => dt.items.add(f));
        const dropEvent = new DragEvent('drop', { bubbles: true, cancelable: true, dataTransfer: dt });
        dropzone.dispatchEvent(new DragEvent('dragenter', { bubbles: true }));
        dropzone.dispatchEvent(new DragEvent('dragover', { bubbles: true, cancelable: true, dataTransfer: dt }));
        dropzone.dispatchEvent(dropEvent);
        toast(`${files.length} Fotos hochgeladen`, 'success');
        return { ok: true, count: files.length };
      } catch (err) {
        console.warn('Vendoo: Drop-Methode fehlgeschlagen:', err);
      }
    }

    toast('Automatischer Upload fehlgeschlagen. Bitte Fotos manuell hochladen.', 'error');
    return { ok: false, count: 0 };
  }

  function findPhotoDropzone() {
    const selectors = [
      '[data-testid="photo-upload"]',
      '[data-testid="file-upload"]',
      '[class*="photo-upload"]',
      '[class*="PhotoUpload"]',
      '[class*="dropzone"]',
      '[class*="Dropzone"]',
      '[class*="media-upload"]',
      '[class*="image-upload"]',
      '.upload-dropzone',
      '[class*="drag-and-drop"]',
    ];
    for (const s of selectors) {
      const el = document.querySelector(s);
      if (el) return el;
    }
    const divs = document.querySelectorAll('div[class]');
    for (const d of divs) {
      if (d.className.match(/photo|upload|drop|media|image/i) && d.offsetHeight > 50) return d;
    }
    return null;
  }

  function findPhotoFileInput() {
    const inputs = document.querySelectorAll('input[type="file"]');
    for (const inp of inputs) {
      if (inp.accept && inp.accept.includes('image')) return inp;
    }
    if (inputs.length) return inputs[0];
    return null;
  }

  // --- Category Picker (in-panel dropdown with Vinted categories) ---

  let selectedVintedCategory = null;

  function initCategoryPicker(container, aiCategory) {
    const input = container.querySelector('#al-d-category');
    const dropdown = container.querySelector('#al-cat-dropdown');
    const display = container.querySelector('#al-cat-selected-display');
    if (!input || !dropdown || !display) return;

    if (aiCategory) {
      serverMatchCategory(aiCategory).then(matches => {
        if (matches.length > 0) selectPickerCategory(matches[0], display);
        renderDropdownResults(matches, dropdown, display);
      });
    }

    input.addEventListener('focus', () => {
      if (input.value.trim().length === 0) renderCategoryTree(dropdown, display);
      else serverMatchCategory(input.value).then(m => renderDropdownResults(m, dropdown, display));
      dropdown.classList.add('open');
    });

    let catSearchTimer;
    input.addEventListener('input', () => {
      clearTimeout(catSearchTimer);
      catSearchTimer = setTimeout(() => {
        const q = input.value.trim();
        if (q.length === 0) renderCategoryTree(dropdown, display);
        else serverMatchCategory(q).then(m => renderDropdownResults(m, dropdown, display));
        dropdown.classList.add('open');
      }, 200);
    });

    document.addEventListener('click', e => {
      if (!container.querySelector('#al-cat-wrap')?.contains(e.target)) dropdown.classList.remove('open');
    });
  }

  function renderDropdownResults(matches, dropdown, display) {
    if (!matches.length) {
      dropdown.innerHTML = '<div style="padding:8px;font-size:11px;color:#aaa;text-align:center">Keine Kategorie gefunden</div>';
      return;
    }
    dropdown.innerHTML = matches.map((m, i) => `
      <div class="al-cat-item" data-idx="${i}">
        <div class="al-cat-item-name">${esc(m.name)}</div>
        <div class="al-cat-item-path">${esc(m.path.slice(0, -1).join(' > '))}</div>
      </div>
    `).join('');
    dropdown.querySelectorAll('.al-cat-item').forEach((el, i) => {
      el.addEventListener('click', e => {
        e.stopPropagation();
        selectPickerCategory(matches[i], display);
        dropdown.classList.remove('open');
      });
    });
  }

  function renderCategoryTree(dropdown, display) {
    let html = '<div class="al-cat-tree">';
    for (const main of VINTED_CATEGORIES) {
      html += `<div class="al-cat-group">`;
      html += `<div class="al-cat-group-hd" data-main="${main.id}"><span class="al-cat-arrow">&#9654;</span> ${esc(main.name)}</div>`;
      html += `<div class="al-cat-group-children" data-main="${main.id}">`;
      if (main.children) {
        for (const sub of main.children) {
          html += `<div class="al-cat-group">`;
          html += `<div class="al-cat-group-hd" data-sub="${sub.id}" style="padding-left:16px"><span class="al-cat-arrow">&#9654;</span> ${esc(sub.name)}</div>`;
          html += `<div class="al-cat-group-children" data-sub="${sub.id}">`;
          if (sub.children) {
            for (const leaf of sub.children) {
              html += `<div class="al-cat-leaf" data-cat-id="${leaf.id}" data-path="${attr([main.name, sub.name, leaf.name].join(' > '))}" data-name="${attr(leaf.name)}">${esc(leaf.name)}</div>`;
            }
          }
          html += '</div></div>';
        }
      }
      html += '</div></div>';
    }
    html += '</div>';
    dropdown.innerHTML = html;

    dropdown.querySelectorAll('.al-cat-group-hd').forEach(hd => {
      hd.addEventListener('click', e => {
        e.stopPropagation();
        const isMain = hd.dataset.main;
        const isSub = hd.dataset.sub;
        const sel = isMain ? `[data-main="${isMain}"]` : `[data-sub="${isSub}"]`;
        const children = hd.nextElementSibling;
        if (children) { children.classList.toggle('open'); hd.classList.toggle('expanded'); }
      });
    });

    dropdown.querySelectorAll('.al-cat-leaf').forEach(leaf => {
      leaf.addEventListener('click', e => {
        e.stopPropagation();
        selectPickerCategory({
          id: +leaf.dataset.catId,
          name: leaf.dataset.name,
          path: leaf.dataset.path.split(' > '),
          pathStr: leaf.dataset.path,
        }, display);
        dropdown.classList.remove('open');
      });
    });
  }

  function selectPickerCategory(cat, display) {
    selectedVintedCategory = cat;
    const input = panel.querySelector('#al-d-category');
    if (input) input.value = cat.name;
    if (display) {
      display.innerHTML = `
        <div class="al-cat-selected">
          <div>
            <div style="font-weight:600">${esc(cat.name)}</div>
            <div class="al-cat-breadcrumb">${esc(cat.path ? cat.path.join(' > ') : cat.name)}</div>
          </div>
          <button class="al-cat-clear" title="Auswahl aufheben">&times;</button>
        </div>
      `;
      display.querySelector('.al-cat-clear')?.addEventListener('click', () => {
        selectedVintedCategory = null;
        display.innerHTML = '';
        if (input) input.value = '';
      });
    }
  }

  // --- Category Selection on Vinted page ---

  async function selectCategory(category) {
    if (!category && !selectedVintedCategory) {
      toast('Keine Kategorie angegeben', 'error');
      return;
    }

    let catData = selectedVintedCategory;
    if (!catData && category) {
      const matches = await serverMatchCategory(category);
      catData = matches?.[0] || null;
    }

    if (!catData || !catData.path?.length) {
      toast('Kategorie "' + category + '" nicht in Vinted-Kategorien gefunden. Bitte manuell wählen.', 'error');
      return;
    }

    const catPath = catData.path;

    const categoryBtn = findCategoryButton();
    if (!categoryBtn) {
      toast('Kategorie-Bereich auf Vinted nicht gefunden. Bitte manuell: ' + catPath.join(' > '), 'error');
      return;
    }

    categoryBtn.click();
    await sleep(1000);

    for (let i = 0; i < catPath.length; i++) {
      const found = await clickCategoryLevel(catPath[i]);
      if (!found) {
        toast(`Ebene "${catPath[i]}" nicht gefunden. Bisher: ${catPath.slice(0, i).join(' > ')}`, 'error');
        return;
      }
      await sleep(600);
    }

    toast('Kategorie: ' + catPath.join(' > '), 'success');
  }

  function findCategoryButton() {
    const selectors = [
      '[data-testid*="catalog"]', '[data-testid*="category"]',
      '[class*="catalog"]', '[class*="Category"]', '[class*="category"]',
    ];
    for (const s of selectors) {
      const el = document.querySelector(s + ' button') || document.querySelector(s);
      if (el && !el.closest('#al-panel')) return el;
    }
    for (const el of document.querySelectorAll('button, [role="button"], a, div[class]')) {
      if (el.closest('#al-panel')) continue;
      const text = el.textContent.trim().toLowerCase();
      if ((text.includes('kategorie') || text.includes('category') || text.includes('katalog'))
          && el.offsetHeight > 0 && el.offsetHeight < 200) return el;
    }
    return null;
  }

  async function clickCategoryLevel(name) {
    const norm = name.toLowerCase().trim();
    const containers = [
      ...document.querySelectorAll('[role="dialog"], [class*="modal"], [class*="overlay"], [class*="catalog"], [class*="category"]'),
      document.body,
    ];
    for (const container of containers) {
      if (!container || container.closest('#al-panel')) continue;
      const clickables = container.querySelectorAll('li, [role="option"], [role="button"], button, a, div[class*="item"], div[class*="option"], span[class*="name"]');
      for (const el of clickables) {
        if (el.closest('#al-panel')) continue;
        const t = el.textContent.trim().toLowerCase();
        if (t === norm || t.startsWith(norm) || norm.startsWith(t)) { el.click(); return true; }
      }
      for (const el of clickables) {
        if (el.closest('#al-panel')) continue;
        const t = el.textContent.trim().toLowerCase();
        if ((t.includes(norm) || norm.includes(t)) && t.length > 1 && t.length < 100) { el.click(); return true; }
      }
    }
    return false;
  }

  // --- Vinted Form Fill ---

  function setNativeValue(el, value) {
    const setter = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(el), 'value')?.set
      || Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value')?.set
      || Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set;
    if (setter) setter.call(el, value);
    else el.value = value;
    el.dispatchEvent(new Event('input', { bubbles: true }));
    el.dispatchEvent(new Event('change', { bubbles: true }));
  }

  function isExtensionElement(el) {
    return !el || Boolean(el.closest?.('#al-panel'));
  }

  function isUsableFormControl(el, expectedTag = '') {
    if (!el || isExtensionElement(el) || el.disabled) return false;
    if (expectedTag && el.tagName?.toLowerCase() !== expectedTag.toLowerCase()) return false;
    return true;
  }

  function normalizedFieldText(value) {
    return String(value || '').replace(/\s+/g, ' ').trim().toLowerCase();
  }

  function getAssociatedControl(label, selector) {
    if (!label) return null;
    if (label.htmlFor) {
      const byFor = document.getElementById(label.htmlFor);
      if (byFor?.matches?.(selector) && isUsableFormControl(byFor)) return byFor;
    }
    const nested = label.querySelector(selector);
    if (isUsableFormControl(nested)) return nested;
    if (label.id && typeof CSS !== 'undefined' && CSS.escape) {
      const escapedId = CSS.escape(label.id);
      const labelledSelector = selector.split(',')
        .map(part => `${part.trim()}[aria-labelledby~="${escapedId}"]`)
        .join(', ');
      const labelled = document.querySelector(labelledSelector);
      if (isUsableFormControl(labelled)) return labelled;
    }
    const sibling = label.nextElementSibling;
    if (sibling) {
      const direct = sibling.matches?.(selector) ? sibling : sibling.querySelector?.(selector);
      if (isUsableFormControl(direct)) return direct;
    }
    const parent = label.parentElement;
    if (parent) {
      const scopedSelector = selector.split(',').map(part => {
        const item = part.trim();
        return `:scope > ${item}, :scope > div > ${item}`;
      }).join(', ');
      const controls = [...parent.querySelectorAll(scopedSelector)]
        .filter(control => isUsableFormControl(control));
      if (controls.length === 1) return controls[0];
    }
    return null;
  }

  function findField(selectors) {
    for (const selector of selectors) {
      for (const el of document.querySelectorAll(selector)) {
        if (isUsableFormControl(el)) return el;
      }
    }
    return null;
  }

  function findByLabel(text, tag) {
    const wanted = normalizedFieldText(text);
    const labels = [...document.querySelectorAll('label')]
      .filter(label => !isExtensionElement(label))
      .sort((a, b) => normalizedFieldText(a.textContent).length - normalizedFieldText(b.textContent).length);
    for (const label of labels) {
      const labelText = normalizedFieldText(label.textContent);
      if (!(labelText === wanted || labelText.startsWith(`${wanted} `) || labelText.startsWith(`${wanted}*`))) continue;
      const control = getAssociatedControl(label, tag);
      if (isUsableFormControl(control, tag)) return control;
    }
    return null;
  }

  function isLikelyTitleField(el) {
    if (!el) return false;
    const identity = normalizedFieldText([
      el.name,
      el.id,
      el.getAttribute?.('data-testid'),
      el.getAttribute?.('aria-label'),
      el.getAttribute?.('placeholder'),
    ].filter(Boolean).join(' '));
    return /(^|[\s_-])(title|titel)([\s_-]|$)/.test(identity);
  }

  function fillVintedForm(fields) {
    let filled = 0;

    const titleEl = findField([
      '[data-testid="title-input"] input',
      '[data-testid*="title" i] input',
      'input[name="title"]',
      'input[id*="title" i]',
      'input[aria-label*="Titel" i]',
      'input[aria-label*="Title" i]',
      'input[placeholder*="Titel" i]',
      'input[placeholder*="Title" i]'
    ]) || findByLabel('Titel', 'input') || findByLabel('Title', 'input');
    if (titleEl && fields.title) { setNativeValue(titleEl, fields.title); filled++; }

    const descEl = findField(['[data-testid="description-input"] textarea', 'textarea[name="description"]', '[class*="Description"] textarea'])
      || findByLabel('Beschreib', 'textarea') || findByLabel('Describe', 'textarea');
    if (descEl && fields.description) { setNativeValue(descEl, fields.description); filled++; }

    const priceEl = findField(['[data-testid="price-input"] input', 'input[name="price"]', '[class*="Price"] input'])
      || findByLabel('Preis', 'input') || findByLabel('Price', 'input');
    if (priceEl && fields.price) {
      setNativeValue(priceEl, String(fields.price).replace(/[^\d.,]/g, '').replace(',', '.'));
      filled++;
    }

    if (fields.tags) {
      const tagEl = findField(['[data-testid="hashtag-input"] input', 'input[name="hashtags"]'])
        || findByLabel('Hashtag', 'input');
      if (tagEl) {
        const tagList = fields.tags.split(/\s+/).filter(Boolean);
        tagList.forEach((tag, i) => {
          setTimeout(() => {
            setNativeValue(tagEl, tag.replace(/^#/, ''));
            tagEl.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter', code: 'Enter', keyCode: 13, bubbles: true }));
          }, i * 250);
        });
        filled++;
      }
    }

    toast(filled > 0 ? `${filled} Felder ausgefüllt` : 'Keine Felder gefunden — richtige Seite?', filled > 0 ? 'success' : 'error');
    return filled;
  }

  // --- Submit / Draft ---

  function clickVintedButton(mode) {
    const allBtns = document.querySelectorAll('button[type="submit"], button[class*="submit"], button[data-testid]');

    if (mode === 'draft') {
      for (const btn of document.querySelectorAll('button, a, [role="button"]')) {
        const text = btn.textContent.trim().toLowerCase();
        if (text.includes('entwurf') || text.includes('draft') || text.includes('save as draft') || text.includes('als entwurf')) {
          btn.click();
          return true;
        }
      }
      toast('Entwurf-Button nicht gefunden. Bitte manuell als Entwurf speichern.', 'error');
      return false;
    }

    if (mode === 'publish') {
      for (const btn of document.querySelectorAll('button, [role="button"]')) {
        const text = btn.textContent.trim().toLowerCase();
        if (text.includes('hochladen') || text.includes('upload') || text.includes('veröffentlichen')
            || text.includes('publish') || text.includes('anzeige aufgeben') || text.includes('list now')) {
          btn.click();
          return true;
        }
      }
      for (const btn of allBtns) {
        if (btn.type === 'submit' && !btn.closest('#al-panel')) {
          btn.click();
          return true;
        }
      }
      toast('Veröffentlichen-Button nicht gefunden. Bitte manuell veröffentlichen.', 'error');
      return false;
    }
    return false;
  }

  // --- Status tracking ---

  async function markStatus(id, status) {
    try {
      await api('/api/publish/mark', 'POST', { listing_id: id, platform: 'vinted', status });
    } catch {}
  }

  // --- Batch ---

  async function startBatch() {
    const ids = [...STATE.selected];
    if (!ids.length) return;

    STATE.batchRunning = true;
    STATE.batchAbort = false;
    STATE.batchProgress = { current: 0, total: ids.length, currentId: null };
    updateFooter();
    showBatchProgress();

    for (let i = 0; i < ids.length; i++) {
      if (STATE.batchAbort) break;

      const id = ids[i];
      STATE.batchProgress.current = i + 1;
      STATE.batchProgress.currentId = id;
      renderQueue();
      updateBatchProgress();

      try {
        const data = await api(`/api/extension/listing/${id}/photos`);
        const l = data.listing;
        const photoFiles = l.photos || [];

        // 1) Upload photos
        logBatchStep(id, 'Fotos hochladen...');
        await uploadPhotos(typeof photoFiles === 'string' ? photoFiles.split(' ').filter(Boolean) : photoFiles);
        await sleep(1500);

        // 2) Fill fields
        logBatchStep(id, 'Felder ausfüllen...');
        fillVintedForm({
          title: l.title, description: l.description,
          price: l.price ? String(l.price) : '',
          condition: l.condition || '', brand: l.brand || '',
          size: l.size || '', tags: (l.tags || []).join(' '),
        });
        await sleep(1000);

        // 3) Category
        if (l.category) {
          logBatchStep(id, 'Kategorie wählen...');
          await selectCategory(l.category);
          await sleep(1000);
        }

        // 4) Submit
        logBatchStep(id, STATE.batchMode === 'draft' ? 'Als Entwurf speichern...' : 'Veröffentlichen...');
        await sleep(500);
        clickVintedButton(STATE.batchMode);
        await markStatus(id, STATE.batchMode === 'draft' ? 'draft' : 'published');
        logBatchItem(id, 'done');

        // Wait for page to process
        await sleep(3000);

      } catch (err) {
        logBatchItem(id, 'error', err.message);
      }

      if (i < ids.length - 1 && !STATE.batchAbort) {
        await countdown(STATE.batchDelay);
      }
    }

    STATE.batchRunning = false;
    STATE.batchProgress.currentId = null;
    updateFooter();
    toast(STATE.batchAbort ? 'Batch abgebrochen' : `${ids.length} Artikel eingetragen!`, STATE.batchAbort ? 'error' : 'success');
    STATE.selected.clear();
    await loadQueue();
    switchTab('queue');
  }

  function showBatchProgress() {
    const view = panel.querySelector('#al-view-batch-progress');
    const modeText = STATE.batchMode === 'draft' ? 'Entwurf' : 'Veröffentlichen';
    view.innerHTML = `
      <div style="padding:12px">
        <div style="font-size:11px;color:#888;text-transform:uppercase;letter-spacing:0.5px;margin-bottom:6px">
          Modus: <strong style="color:${STATE.batchMode === 'draft' ? '#2c6e49' : '#c77b2a'}">${modeText}</strong>
        </div>
        <div class="al-progress">
          <div class="al-progress-bar"><div class="al-progress-fill" id="al-bp-fill" style="width:0%"></div></div>
          <div class="al-progress-text">
            <span id="al-bp-text">0 / ${STATE.batchProgress.total}</span>
            <span id="al-bp-percent">0%</span>
          </div>
        </div>
        <div class="al-countdown" id="al-countdown" style="display:none">
          <div class="al-countdown-label">Nächster Artikel in</div>
          <span id="al-cd-time">--</span>s
        </div>
        <div id="al-bp-log" style="margin-top:8px;font-size:11px;color:#888;max-height:250px;overflow-y:auto"></div>
      </div>
    `;
    switchToView('batch-progress');
    panel.querySelector('#al-footer').style.display = '';
  }

  function updateBatchProgress() {
    const { current, total } = STATE.batchProgress;
    const pct = Math.round((current / total) * 100);
    const fill = panel.querySelector('#al-bp-fill');
    const text = panel.querySelector('#al-bp-text');
    const percent = panel.querySelector('#al-bp-percent');
    if (fill) fill.style.width = pct + '%';
    if (text) text.textContent = `${current} / ${total}`;
    if (percent) percent.textContent = pct + '%';
  }

  function logBatchStep(id, step) {
    const log = panel.querySelector('#al-bp-log');
    if (!log) return;
    const listing = STATE.queue.find(l => l.id === id);
    const title = listing ? listing.title : `#${id}`;
    log.innerHTML += `<div style="margin-bottom:2px;color:#aaa">&#8226; ${esc(title.substring(0, 30))}... ${step}</div>`;
    log.scrollTop = log.scrollHeight;
  }

  function logBatchItem(id, status, msg) {
    const log = panel.querySelector('#al-bp-log');
    if (!log) return;
    const listing = STATE.queue.find(l => l.id === id);
    const title = listing ? listing.title : `#${id}`;
    const icon = status === 'done' ? '&#10003;' : '&#10007;';
    const color = status === 'done' ? '#2c6e49' : '#c0392b';
    log.innerHTML += `<div style="margin-bottom:3px;font-weight:600"><span style="color:${color}">${icon}</span> ${esc(title)}${msg ? ' — ' + esc(msg) : ''}</div>`;
    log.scrollTop = log.scrollHeight;
  }

  function countdown(seconds) {
    return new Promise(resolve => {
      const cdEl = panel.querySelector('#al-countdown');
      const timeEl = panel.querySelector('#al-cd-time');
      if (!cdEl) { setTimeout(resolve, seconds * 1000); return; }
      cdEl.style.display = '';
      let remaining = seconds;
      timeEl.textContent = remaining;
      const iv = setInterval(() => {
        remaining--;
        timeEl.textContent = remaining;
        if (remaining <= 0 || STATE.batchAbort) {
          clearInterval(iv);
          cdEl.style.display = 'none';
          resolve();
        }
      }, 1000);
    });
  }

  // --- Util ---

  function esc(s) { const d = document.createElement('div'); d.textContent = s; return d.innerHTML; }
  function attr(s) { return String(s).replace(/"/g, '&quot;'); }

  // --- Init ---

  async function init() {
    await loadSettings();
    if (!panel) createPanel();
    await checkConnection();
    if (STATE.connected) {
      await loadQueue();
      await sendDiagnosticHeartbeat();
      const pending = await storageGet(['pendingFillListingId', 'pendingFillIncludePhotos', 'pendingOpenListingId']);
      if (pending.pendingFillListingId) {
        const listing = STATE.queue.find(item => item.id === Number(pending.pendingFillListingId));
        if (listing) {
          const includePhotos = pending.pendingFillIncludePhotos === true;
          await storageSet({ pendingFillListingId: null, pendingFillIncludePhotos: null });
          await fillListingData(listing, { includePhotos });
          showDetail(listing.id);
        }
      }
      if (pending.pendingOpenListingId) {
        const detailListing = STATE.queue.find(item => item.id === Number(pending.pendingOpenListingId));
        await storageSet({ pendingOpenListingId: null });
        if (detailListing) showDetail(detailListing.id);
      }
    }
  }

  const runtime = browserApi?.runtime || chromeApi?.runtime;
  runtime?.onMessage?.addListener((message, _sender, sendResponse) => {
    if (message?.type !== 'vendoo-fill-listing') return;
    (async () => {
      const listing = STATE.queue.find(item => item.id === Number(message.listingId));
      if (!listing) throw new Error('Listing nicht in der Warteschlange gefunden');
      await fillListingData(listing, { includePhotos: message.includePhotos === true });
      showDetail(listing.id);
      return { ok: true };
    })().then(sendResponse).catch(error => sendResponse({ ok: false, error: error.message }));
    return true;
  });

  setInterval(async () => {
    if (!STATE.connected) await checkConnection();
    if (STATE.connected) await sendDiagnosticHeartbeat();
  }, 60 * 1000);

  if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', init);
  else init();
})();

