/**
 * 熊猫助手 1688 单商品事实采集器。
 * 只回传页面中真实存在的字段，不生成关键词、卖点或缺失规格。
 */
(function() {
  'use strict';

  if (!/\.1688\.com$/i.test(location.hostname) || !/\/offer\/\d+/i.test(location.pathname)) return;

  var COLLECTOR_VERSION = '5.2.16';
  var MAX_SCRIPT_SIZE = 2500000;

  function clean(value, limit) {
    var text = String(value == null ? '' : value).replace(/\u00a0/g, ' ').replace(/\s+/g, ' ').trim();
    return limit ? text.slice(0, limit) : text;
  }

  function absoluteUrl(value) {
    var url = clean(value, 2000);
    if (!url || url.indexOf('data:') === 0 || url.indexOf('blob:') === 0) return '';
    if (url.indexOf('//') === 0) url = 'https:' + url;
    try { return new URL(url, location.href).href; } catch (error) { return ''; }
  }

  function mediaUrl(value) {
    var url = absoluteUrl(value);
    if (!url || /sprite|icon|logo|avatar|placeholder|loading/i.test(url)) return '';
    return url.split('?')[0];
  }

  function pushUnique(list, value) {
    var url = mediaUrl(value);
    if (url && list.indexOf(url) === -1) list.push(url);
  }

  function numberOrNull(value) {
    if (value === undefined || value === null || value === '') return null;
    var match = String(value).replace(',', '.').match(/-?\d+(?:\.\d+)?/);
    if (!match) return null;
    var number = parseFloat(match[0]);
    return Number.isFinite(number) ? number : null;
  }

  function offerId() {
    var match = location.pathname.match(/\/offer\/(\d+)/i);
    return match ? match[1] : '';
  }

  function draftId() {
    try { return new URL(location.href).searchParams.get('qydz_draft_id') || ''; } catch (error) { return ''; }
  }

  function extractBalanced(text, start) {
    var first = text[start];
    if (first !== '{' && first !== '[') return '';
    var open = first;
    var close = first === '{' ? '}' : ']';
    var depth = 0;
    var quote = '';
    var escaped = false;
    for (var i = start; i < text.length; i += 1) {
      var char = text[i];
      if (quote) {
        if (escaped) escaped = false;
        else if (char === '\\') escaped = true;
        else if (char === quote) quote = '';
        continue;
      }
      if (char === '"' || char === "'") { quote = char; continue; }
      if (char === open) depth += 1;
      if (char === close) {
        depth -= 1;
        if (depth === 0) return text.slice(start, i + 1);
      }
    }
    return '';
  }

  function valueAfterKey(text, key) {
    var needles = ['"' + key + '"', "'" + key + "'", key];
    for (var n = 0; n < needles.length; n += 1) {
      var index = text.indexOf(needles[n]);
      while (index >= 0) {
        var colon = text.indexOf(':', index + needles[n].length);
        if (colon < 0 || colon - index > 80) break;
        var start = colon + 1;
        while (/\s/.test(text[start] || '')) start += 1;
        var json = extractBalanced(text, start);
        if (json) {
          try { return JSON.parse(json); } catch (error) {}
        }
        index = text.indexOf(needles[n], index + needles[n].length);
      }
    }
    return null;
  }

  function assignedJson(text, names) {
    for (var i = 0; i < names.length; i += 1) {
      var index = text.indexOf(names[i]);
      if (index < 0) continue;
      var equals = text.indexOf('=', index + names[i].length);
      if (equals < 0 || equals - index > 80) continue;
      var start = equals + 1;
      while (/\s/.test(text[start] || '')) start += 1;
      var json = extractBalanced(text, start);
      if (json) {
        try { return JSON.parse(json); } catch (error) {}
      }
    }
    return null;
  }

  function collectEmbeddedData() {
    var selected = {};
    var jsonLd = [];
    var stateRoots = [];
    var keys = ['skuMap','skuProps','skuRangePrices','priceRanges','productInfo','offer','offerInfo','images','videos','video','shippingInfo'];
    var scripts = document.querySelectorAll('script');
    for (var i = 0; i < scripts.length; i += 1) {
      var script = scripts[i];
      var text = script.textContent || '';
      if (!text || text.length > MAX_SCRIPT_SIZE) continue;
      var type = clean(script.getAttribute('type'), 100).toLowerCase();
      if (type === 'application/ld+json') {
        try { jsonLd.push(JSON.parse(text)); } catch (error) {}
        continue;
      }
      if (type === 'application/json') {
        try { stateRoots.push(JSON.parse(text)); } catch (error) {}
      }
      var assigned = assignedJson(text, ['window.__DATA__','window.__INIT_DATA__','window.iDetailData','window.__offer_detail__','__NEXT_DATA__']);
      if (assigned) stateRoots.push(assigned);
      keys.forEach(function(key) {
        if (selected[key] !== undefined) return;
        var value = valueAfterKey(text, key);
        if (value !== null) selected[key] = value;
      });
    }

    var aliases = {
      skumap:'skuMap', skumodel:'skuMap', skus:'skus', skudata:'skus',
      skuprops:'skuProps', skuattributes:'skuProps',
      skurangeprices:'skuRangePrices', priceranges:'priceRanges',
      productinfo:'productInfo', offerinfo:'offerInfo', offer:'offer',
      detailimages:'detailImages', descriptionimages:'detailImages',
      videos:'videos', video:'video', shippinginfo:'shippingInfo'
    };
    var visited = 0;
    function scan(value, depth) {
      if (!value || typeof value !== 'object' || depth > 7 || visited > 18000) return;
      visited += 1;
      Object.keys(value).forEach(function(key) {
        var normalized = String(key).replace(/[^a-z]/gi, '').toLowerCase();
        var target = aliases[normalized];
        if (target && selected[target] === undefined) selected[target] = value[key];
        scan(value[key], depth + 1);
      });
    }
    stateRoots.forEach(function(root) { scan(root, 0); });
    return { selected: selected, json_ld: jsonLd.slice(0, 10) };
  }

  function compactRaw(value, depth) {
    depth = depth || 0;
    if (depth > 7 || value === null || value === undefined) return null;
    if (typeof value === 'string') return value.slice(0, 8000);
    if (typeof value !== 'object') return value;
    if (Array.isArray(value)) return value.slice(0, 200).map(function(item) { return compactRaw(item, depth + 1); });
    var output = {};
    Object.keys(value).slice(0, 200).forEach(function(key) { output[key] = compactRaw(value[key], depth + 1); });
    return output;
  }

  function firstObject() {
    for (var i = 0; i < arguments.length; i += 1) {
      var value = arguments[i];
      if (value && typeof value === 'object' && !Array.isArray(value)) return value;
    }
    return {};
  }

  function firstValue() {
    for (var i = 0; i < arguments.length; i += 1) {
      if (arguments[i] !== undefined && arguments[i] !== null && arguments[i] !== '') return arguments[i];
    }
    return '';
  }

  function meta(name) {
    var element = document.querySelector('meta[property="' + name + '"],meta[name="' + name + '"]');
    return element ? clean(element.getAttribute('content'), 4000) : '';
  }

  function collectImageElements(selectors, limit) {
    var images = [];
    selectors.forEach(function(selector) {
      document.querySelectorAll(selector).forEach(function(image) {
        if (images.length >= limit) return;
        var width = image.naturalWidth || image.width || 0;
        var height = image.naturalHeight || image.height || 0;
        if ((width && width < 80) || (height && height < 80)) return;
        pushUnique(images, image.currentSrc || image.getAttribute('src') || image.getAttribute('data-src') || image.getAttribute('data-lazy-src') || image.getAttribute('data-ks-lazyload'));
      });
    });
    return images.slice(0, limit);
  }

  function addAttribute(list, name, value) {
    var key = clean(name, 120).replace(/[:：]$/, '');
    var itemValue = clean(value, 500);
    if (!key || !itemValue || key === itemValue) return;
    if (!list.some(function(item) { return item.name === key && item.value === itemValue; })) list.push({ name: key, value: itemValue });
  }

  function collectAttributes() {
    var attributes = [];
    var selectors = ['.offer-attr-item','.mod-detail-attributes li','.detail-attribute li','[class*="offer-attr"] [class*="item"]','[class*="attribute"] li','[class*="property"] li','[class*="param"] li','table tr'];
    selectors.forEach(function(selector) {
      document.querySelectorAll(selector).forEach(function(element) {
        var cells = element.querySelectorAll('th,td');
        if (cells.length >= 2) { addAttribute(attributes, cells[0].textContent, cells[1].textContent); return; }
        var label = element.querySelector('dt,[class*="label"],[class*="name"],[class*="key"]');
        var value = element.querySelector('dd,[class*="value"],[class*="text"],[class*="content"]');
        if (label && value && label !== value) { addAttribute(attributes, label.textContent, value.textContent); return; }
        var text = clean(element.textContent, 700);
        var match = text.match(/^([^:：]{1,80})[:：]\s*(.{1,500})$/);
        if (match) addAttribute(attributes, match[1], match[2]);
      });
    });
    return attributes.slice(0, 200);
  }

  function normalizeSkuDimensions(raw) {
    var list = Array.isArray(raw) ? raw : [];
    return list.map(function(item) {
      var values = item.values || item.value || item.options || item.children || [];
      return {
        name: clean(item.name || item.prop || item.propName || item.title || item.attributeName, 100),
        values: (Array.isArray(values) ? values : []).map(function(value) {
          if (typeof value === 'string') return { name: clean(value, 150), id: '', image: '' };
          return {
            name: clean(value.name || value.value || value.text || value.title, 150),
            id: clean(value.id || value.valueId || value.specId || value.propValueId, 100),
            image: mediaUrl(value.image || value.imageUrl || value.picUrl || value.src)
          };
        }).filter(function(value) { return value.name; })
      };
    }).filter(function(item) { return item.name && item.values.length; });
  }

  function normalizeSkuCombinations(selected, dimensions) {
    var result = [];
    var valueMap = {};
    dimensions.forEach(function(dimension) {
      dimension.values.forEach(function(value) {
        if (value.id) valueMap[value.id] = { name: dimension.name, value: value.name, source_id: value.id };
      });
    });
    function add(raw, key) {
      if (!raw || typeof raw !== 'object') return;
      var attributes = raw.attributes || raw.properties || raw.props || [];
      if (!Array.isArray(attributes) && attributes && typeof attributes === 'object') {
        attributes = Object.keys(attributes).map(function(name) { return { name: name, value: attributes[name] }; });
      }
      attributes = (Array.isArray(attributes) ? attributes : []).map(function(item) {
        return { name: clean(item.name || item.key || item.prop || item.propertyName, 100), value: clean(item.value || item.text || item.valueName || item.propertyValue, 150), source_id: clean(item.id || item.valueId || item.specId, 100) };
      }).filter(function(item) { return item.name || item.value; });
      if (!attributes.length && key) {
        var ids = String(key).match(/[A-Za-z0-9_-]{2,}/g) || [];
        attributes = ids.map(function(id) { return valueMap[id] || null; }).filter(Boolean);
        if (!attributes.length) attributes = [{ name: '', value: clean(key, 300), source_id: '' }];
      }
      result.push({
        sku_id: clean(raw.skuId || raw.sku_id || raw.id || key, 150),
        sku_code: clean(raw.skuCode || raw.code || raw.specId, 150),
        attributes: attributes,
        price: numberOrNull(firstValue(raw.price, raw.discountPrice, raw.salePrice, raw.unitPrice, raw.skuPrice)),
        inventory: numberOrNull(firstValue(raw.inventory, raw.stock, raw.canBookCount, raw.amountOnSale, raw.quantity)),
        image: mediaUrl(raw.image || raw.imageUrl || raw.picUrl || raw.variantImageUrl)
      });
    }
    var list = selected.skus;
    if (Array.isArray(list)) list.forEach(function(item) { add(item, ''); });
    var map = selected.skuMap;
    if (map && typeof map === 'object' && !Array.isArray(map)) Object.keys(map).forEach(function(key) { add(map[key], key); });
    return result;
  }

  function normalizePriceRanges(raw) {
    var list = Array.isArray(raw) ? raw : [];
    return list.map(function(item) {
      return { minimum_quantity: numberOrNull(firstValue(item.minimum_quantity, item.startQuantity, item.start, item.beginAmount, item.minQuantity)), price: numberOrNull(firstValue(item.price, item.value, item.unitPrice)) };
    }).filter(function(item) { return item.price !== null; });
  }

  function collectVideos(selected) {
    var videos = [];
    pushUnique(videos, meta('og:video'));
    pushUnique(videos, meta('og:video:url'));
    document.querySelectorAll('video,video source').forEach(function(element) { pushUnique(videos, element.currentSrc || element.src || element.getAttribute('src')); });
    [selected.videos, selected.video].forEach(function(value) {
      if (Array.isArray(value)) value.forEach(function(item) { pushUnique(videos, typeof item === 'string' ? item : item.url || item.videoUrl || item.src); });
      else if (value) pushUnique(videos, typeof value === 'string' ? value : value.url || value.videoUrl || value.src);
    });
    return videos.slice(0, 20);
  }

  function collectDescription() {
    var selectors = ['#desc-lazyload-container','.desc-lazyload-container','.detail-description-content','.detail-desc','.offer-detail','[class*="description"]','[class*="detail-content"]'];
    var chunks = [];
    selectors.forEach(function(selector) {
      document.querySelectorAll(selector).forEach(function(element) {
        var text = clean(element.innerText || element.textContent, 3000);
        if (text.length >= 12 && chunks.indexOf(text) === -1) chunks.push(text);
      });
    });
    return clean(chunks.join('。'), 8000);
  }

  function collectShippingText() {
    var selectors = ['[class*="delivery"]','[class*="shipping"]','[class*="logistics"]','[class*="send-address"]','[class*="freight"]'];
    var parts = [];
    selectors.forEach(function(selector) {
      document.querySelectorAll(selector).forEach(function(element) {
        var text = clean(element.textContent, 500);
        if (text && text.length < 500 && parts.indexOf(text) === -1) parts.push(text);
      });
    });
    return clean(parts.join('；'), 1000);
  }

  function extractProduct() {
    var embedded = collectEmbeddedData();
    var selected = embedded.selected;
    var productInfo = firstObject(selected.productInfo, selected.offerInfo, selected.offer);
    var jsonProduct = embedded.json_ld.find(function(item) { return item && (item['@type'] === 'Product' || (Array.isArray(item['@graph']) && item['@graph'].length)); }) || {};
    if (Array.isArray(jsonProduct['@graph'])) jsonProduct = jsonProduct['@graph'].find(function(item) { return item && item['@type'] === 'Product'; }) || jsonProduct;

    var titleElement = document.querySelector('[data-testid="productTitle"],.offer-title,.mod-detail-title .title,.title-text,h1');
    var title = clean(firstValue(productInfo.title, productInfo.subject, productInfo.offerTitle, jsonProduct.name, meta('og:title'), titleElement && titleElement.textContent), 500);
    if (/1688|阿里巴巴/.test(title) && title.length < 12) title = '';

    var gallery = [];
    var candidateImages = firstValue(productInfo.images, productInfo.image, selected.images, jsonProduct.image, []);
    (Array.isArray(candidateImages) ? candidateImages : [candidateImages]).forEach(function(item) { pushUnique(gallery, typeof item === 'string' ? item : item.url || item.src || item.imageUrl); });
    collectImageElements(['.detail-gallery img','[data-testid="productImage"] img','.mod-detail-gallery img','[class*="gallery"] img','img[data-role="main-img"]'],100).forEach(function(url) { pushUnique(gallery, url); });
    pushUnique(gallery, meta('og:image'));

    var detailImages = collectImageElements(['#desc-lazyload-container img','.desc-lazyload-container img','.detail-description-content img','.detail-desc img','.offer-detail img','[class*="description"] img'],200);
    var selectedDetailImages = selected.detailImages;
    if (Array.isArray(selectedDetailImages)) selectedDetailImages.forEach(function(item) { pushUnique(detailImages, typeof item === 'string' ? item : item.url || item.src); });

    var attributes = collectAttributes();
    var dimensions = normalizeSkuDimensions(selected.skuProps || productInfo.skuProps || []);
    var combinations = normalizeSkuCombinations({ skuMap: selected.skuMap || productInfo.skuMap, skus: selected.skus || productInfo.skus }, dimensions);
    var priceElement = document.querySelector('[data-testid="price"],.mod-detail-price .price,[class*="price"] [class*="amount"],[class*="Price"]');
    var price = numberOrNull(firstValue(productInfo.price, productInfo.offerPrice, productInfo.minPrice, jsonProduct.offers && jsonProduct.offers.price, priceElement && priceElement.textContent));
    var priceRanges = normalizePriceRanges(selected.skuRangePrices || selected.priceRanges || productInfo.priceRanges || []);
    var shippingText = collectShippingText();
    var inventoryMatch = clean(document.body.innerText, 200000).match(/(?:库存|可售)\s*[:：]?\s*(\d+)/);
    var deliveryMatch = shippingText.match(/(?:发货|交期|出货)[^；。]{0,60}/);
    var shipFromMatch = shippingText.match(/(?:发货地|发货地址|从)[^；。]{0,80}/);

    return {
      offer_id: offerId(),
      draft_id: draftId(),
      source_platform: '1688',
      url: 'https://detail.1688.com/offer/' + offerId() + '.html',
      title: title,
      name: title,
      main_image: gallery[0] || '',
      gallery_images: gallery,
      detail_images: detailImages,
      video_urls: collectVideos(selected),
      price: price,
      currency: 'CNY',
      price_ranges: priceRanges,
      sku_dimensions: dimensions,
      sku_combinations: combinations,
      attributes: attributes,
      inventory: inventoryMatch ? parseInt(inventoryMatch[1],10) : null,
      inventory_text: inventoryMatch ? inventoryMatch[0] : '',
      shipping_info: shippingText,
      ship_from: shipFromMatch ? shipFromMatch[0] : '',
      delivery_time: deliveryMatch ? deliveryMatch[0] : '',
      description_text: collectDescription(),
      raw_page_data: {
        page_title: document.title,
        meta: { title: meta('og:title'), image: meta('og:image'), description: meta('description') },
        json_ld: compactRaw(embedded.json_ld),
        embedded: compactRaw(selected)
      },
      collected_at: new Date().toISOString(),
      collector_version: COLLECTOR_VERSION
    };
  }

  function toast(message, type) {
    var old = document.getElementById('qydz-1688-toast');
    if (old) old.remove();
    var element = document.createElement('div');
    element.id = 'qydz-1688-toast';
    element.textContent = message;
    element.style.cssText = 'position:fixed;top:20px;right:20px;z-index:2147483647;max-width:380px;padding:11px 16px;border-radius:5px;color:#fff;background:' + (type === 'error' ? '#b42318' : type === 'warning' ? '#9a6700' : '#087f5b') + ';font:14px/1.5 Microsoft YaHei,sans-serif;box-shadow:0 8px 24px rgba(0,0,0,.2)';
    document.documentElement.appendChild(element);
    setTimeout(function() { element.remove(); }, 3500);
  }

  function cacheLocally(product) {
    chrome.runtime.sendMessage({ action: 'cacheScrapeData', data: product }, function() {});
  }

  function sendProduct(product) {
    if (!product.title) { toast('未读取到商品标题，请等待页面加载后重试', 'error'); return; }
    chrome.runtime.sendMessage({ action: 'forwardScrapeData', data: product, draft_id: product.draft_id }, function(response) {
      if (chrome.runtime.lastError) {
        cacheLocally(product);
        toast('采集结果已暂存，连接恢复后可重试', 'warning');
        return;
      }
      if (response && response.success) {
        toast('货源快照已保存', 'success');
      } else {
        cacheLocally(product);
        toast(response && response.message ? response.message : '回传失败，结果已暂存', 'warning');
      }
    });
  }

  function collectNow() {
    toast('正在读取1688商品数据', 'success');
    setTimeout(function() { sendProduct(extractProduct()); }, 80);
  }

  function addButton() {
    if (document.getElementById('qydz-collect-btn')) return;
    var button = document.createElement('button');
    button.id = 'qydz-collect-btn';
    button.type = 'button';
    button.textContent = '熊猫采集';
    button.style.cssText = 'position:fixed;right:24px;bottom:28px;z-index:2147483646;height:40px;padding:0 16px;border:0;border-radius:5px;background:#1769aa;color:#fff;font:600 14px Microsoft YaHei,sans-serif;box-shadow:0 8px 24px rgba(0,0,0,.2);cursor:pointer';
    button.addEventListener('click', collectNow);
    document.documentElement.appendChild(button);
  }

  function autoCollect() {
    var params;
    try { params = new URL(location.href).searchParams; } catch (error) { return; }
    if (params.get('_qydz_scrape') !== '1' || window.__QYDZ_1688_AUTO_COLLECT_SENT__) return;
    var attempts = 0;
    var delays = [900, 2000, 4000, 7000, 10000];
    function run() {
      attempts += 1;
      var product = extractProduct();
      if (product.title && (product.main_image || product.gallery_images.length)) {
        window.__QYDZ_1688_AUTO_COLLECT_SENT__ = true;
        sendProduct(product);
      } else if (attempts < delays.length) {
        setTimeout(run, delays[attempts]);
      } else {
        toast('页面数据未加载完整，请点击右下角“熊猫采集”重试', 'warning');
      }
    }
    setTimeout(run, delays[0]);
  }

  chrome.runtime.onMessage.addListener(function(request, sender, sendResponse) {
    if (request && request.action === 'scrape1688Product') {
      var product = extractProduct();
      sendResponse({ success: Boolean(product.title), data: product });
      if (product.title) sendProduct(product);
      return true;
    }
  });

  addButton();
  autoCollect();
})();
