// routes/manageProducts.js
const express = require('express');
const axios = require('axios');
const { v4: uuid } = require('uuid');
const { getToken } = require('../tokenStore');
const { log } = require('../logger');
const crypto = require('crypto');
const router = express.Router();

const {
  createJob,
  updateJob,
  appendJobLog,
  recordProductResult,
  recordProductError,
  finishJob,
  cancelJob,
  isJobCancelled,
  getJob,
  listJobs,
} = require('../jobStore');

const seo_llm_client = axios.create({
  baseURL: 'https://llm.thedomainnest.com',
  headers: { 'Content-Type': 'application/json' },
  timeout: 0,
});

function slugify(str) {
  return str
    .toString()
    .trim()
    .toLowerCase()
    .replace(/[^a-z0-9]+/g, '-')
    .replace(/^-+|-+$/g, '');
}

function extractFirstJsonObject(text) {
  if (typeof text !== 'string') return text;
  let s = text.trim()
    .replace(/^```json\s*/i, '')
    .replace(/^```\s*/i, '')
    .replace(/```$/i, '')
    .trim();
  const start = s.indexOf('{');
  const end = s.lastIndexOf('}');
  if (start === -1 || end === -1 || end <= start) return null;
  s = s.slice(start, end + 1);
  s = s.replace(/(\{|,)\s*(seo_title|seo_description)\s*:/g, '$1"$2":');
  s = s.replace(/"seo_description\s*:\s*/g, '"seo_description":');
  return s;
}

// ---------------------------------------------------------------------------
// Fetch all products for a brand from Turn14
// ---------------------------------------------------------------------------
const GetAllProductsOfBranch = async (brandId, turn14accessToken, shop, jobId) => {
  console.log(`\n📦 [TURN14-FETCH] ========================================`);
  console.log(`📦 [TURN14-FETCH] Fetching products for brand ID: ${brandId}`);
  console.log(`📦 [TURN14-FETCH] Shop: ${shop}`);
  console.log(`📦 [TURN14-FETCH] Job ID: ${jobId}`);
  console.log(`📦 [TURN14-FETCH] Token (first 20 chars): ${turn14accessToken?.slice(0, 20)}...`);
  console.log(`📦 [TURN14-FETCH] URL: https://turn14.data4autos.com/v1/items/brandallitemswithfitment/${brandId}`);

  try {
    appendJobLog(jobId, `[FETCH] Fetching products for brand ${brandId} from Turn14...`);
    const fetchStart = Date.now();
    const res = await fetch(
      `https://turn14.data4autos.com/v1/items/brandallitemswithfitment/${brandId}`,
      {
        headers: {
          Authorization: `Bearer ${turn14accessToken}`,
          'Content-Type': 'application/json',
        },
      }
    );

    console.log(`📦 [TURN14-FETCH] HTTP status: ${res.status} ${res.statusText}`);
    console.log(`📦 [TURN14-FETCH] Response time: ${Date.now() - fetchStart}ms`);

    if (!res.ok) {
      console.error(`❌ [TURN14-FETCH] Non-200 response: ${res.status}`);
    }

    const res_data = await res.json();
    const data = res_data.items || [];
    const fitmentTags = res_data.fitmentTags || [];

    console.log(`📦 [TURN14-FETCH] Raw items in response: ${data.length}`);
    console.log(`📦 [TURN14-FETCH] FitmentTags count: ${fitmentTags.length}`);

    const validItems = Array.isArray(data)
      ? data.filter(item => item && item.id && item.attributes)
      : [];

    console.log(`📦 [TURN14-FETCH] Valid items (have id + attributes): ${validItems.length}`);
    console.log(`📦 [TURN14-FETCH] Sample item IDs: ${validItems.slice(0, 5).map(i => i.id).join(', ')}`);
    console.log(`📦 [TURN14-FETCH] ========================================\n`);

    appendJobLog(jobId, `[FETCH-OK] Found ${validItems.length} products for brand ${brandId}`);
    return { items: validItems, fitmentTags };
  } catch (err) {
    console.error(`❌ [TURN14-FETCH] Exception fetching brand ${brandId}: ${err.message}`);
    console.error(`❌ [TURN14-FETCH] Stack: ${err.stack}`);
    appendJobLog(jobId, `[FETCH-FAIL] Error fetching brand ${brandId}: ${err.message}`);
    return null;
  }
};

// ---------------------------------------------------------------------------
// Add one product to Shopify store
// ---------------------------------------------------------------------------
const AddProductToStore = async (shop, accessToken, product, jobId, locationId) => {
  const SHOP = shop;
  const ACCESS_TOKEN = accessToken;
  const item = product;
  const attrs = item.attributes;

  const productLabel = attrs.product_name || attrs.part_number || `Item ${item.id}`;

  console.log(`\n🛒 [PRODUCT-START] ============================================`);
  console.log(`🛒 [PRODUCT-START] Product: ${productLabel}`);
  console.log(`🛒 [PRODUCT-START] Part Number: ${attrs.part_number || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Mfr Part Number: ${attrs.mfr_part_number || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Turn14 Item ID: ${item.id}`);
  console.log(`🛒 [PRODUCT-START] Brand: ${attrs.brand || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Category: ${attrs.category || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Subcategory: ${attrs.subcategory || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Price: ${attrs.price || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Compare Price: ${attrs.compare_price || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Purchase Cost: ${attrs.purchase_cost || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Barcode: ${attrs.barcode || 'N/A'}`);
  console.log(`🛒 [PRODUCT-START] Images count: ${(attrs.files || []).filter(f => f.type === 'Image').length}`);
  console.log(`🛒 [PRODUCT-START] Shop: ${SHOP}`);
  console.log(`🛒 [PRODUCT-START] Location ID: ${locationId || 'NOT SET'}`);

  // Inventory quantity
  const inventoryData = attrs.inventorydata?.inventory || {};
  const totalQuantity = Object.values(inventoryData).reduce((sum, val) => sum + val, 0);
  console.log(`🛒 [PRODUCT-START] Inventory data: ${JSON.stringify(inventoryData)}`);
  console.log(`🛒 [PRODUCT-START] Total quantity: ${totalQuantity}`);

  // SEO (stubbed — returns empty so we use defaults)
  let parsed = { seo_title: '', seo_description: '' };
  const { seo_title, seo_description } = parsed;

  // Fitment tags
  const globalUniqueFitmentMap = { make: new Set(), model: new Set(), year: new Set(), drive: new Set(), baseModel: new Set() };
  const tags_raw = attrs?.fitmmentTags || {};
  for (const key in globalUniqueFitmentMap) {
    if (tags_raw[key]) tags_raw[key].forEach(v => globalUniqueFitmentMap[key].add(v));
  }
  const convertedFitment = {};
  for (const key in globalUniqueFitmentMap) convertedFitment[key] = Array.from(globalUniqueFitmentMap[key]);
  const allFitmentTags = Array.from(new Set(Object.values(convertedFitment).flat()));
  console.log(`🔖 [PRODUCT-TAGS] Fitment makes: ${convertedFitment.make?.join(', ') || 'none'}`);
  console.log(`🔖 [PRODUCT-TAGS] Fitment models: ${convertedFitment.model?.slice(0, 10).join(', ') || 'none'}${convertedFitment.model?.length > 10 ? ` (+${convertedFitment.model.length - 10} more)` : ''}`);
  console.log(`🔖 [PRODUCT-TAGS] Fitment years: ${convertedFitment.year?.slice(0, 5).join(', ') || 'none'}${convertedFitment.year?.length > 5 ? ` (+${convertedFitment.year.length - 5} more)` : ''}`);
  console.log(`🔖 [PRODUCT-TAGS] Total fitment tags: ${allFitmentTags.length}`);

  const client = axios.create({
    baseURL: `https://${SHOP}/admin/api/2025-10/graphql.json`,
    headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN, 'Content-Type': 'application/json' },
  });

  try {
    // ── STEP 1: Collections ──────────────────────────────────────────────────
    const category = attrs.category || '';
    const subcategory = attrs.subcategory || '';
    const brand = attrs.brand || '';
    const subcats = subcategory.split(/[,\/]/).map(s => s.trim()).filter(Boolean);
    const collectionTitles = Array.from(new Set([category, ...subcats, brand, ...allFitmentTags].filter(Boolean)));

    console.log(`📁 [COLLECTIONS] Titles to find/create: [${collectionTitles.join(' | ')}]`);
    console.log(`📁 [COLLECTIONS] Total collections needed: ${collectionTitles.length}`);

    const collectionIds = [];

    for (const title of collectionTitles) {
      console.log(`📁 [COLLECTIONS] Looking up: "${title}"`);
      const lookupResp = await client.post('', {
        query: `query { collections(first: 1, query: "title:\\"${title}\\" AND collection_type:manual") { nodes { id } } }`
      });
      const existing = lookupResp.data.data.collections.nodes;
      if (existing.length) {
        console.log(`📁 [COLLECTIONS]   ✅ Found existing: ${existing[0].id}`);
        collectionIds.push(existing[0].id);
        continue;
      }
      console.log(`📁 [COLLECTIONS]   ➕ Creating new collection: "${title}"`);
      const createResp = await client.post('', {
        query: `mutation collectionCreate($input: CollectionInput!) { collectionCreate(input: $input) { collection { id } userErrors { field message } } }`,
        variables: { input: { title } },
      });
      const createData = createResp.data.data.collectionCreate;
      if (createData.userErrors.length) {
        console.error(`📁 [COLLECTIONS]   ❌ Failed to create "${title}": ${JSON.stringify(createData.userErrors)}`);
        throw new Error(`Could not create collection "${title}": ${createData.userErrors.map(e => e.message).join(', ')}`);
      }
      console.log(`📁 [COLLECTIONS]   ✅ Created: ${createData.collection.id}`);
      collectionIds.push(createData.collection.id);
    }

    console.log(`📁 [COLLECTIONS] Done. ${collectionIds.length} collection IDs collected`);

    // ── STEP 2: Build tags ───────────────────────────────────────────────────
    const productTags = [
      attrs.category,
      ...subcats,
      ...allFitmentTags,
      attrs.brand,
      attrs.part_number,
      attrs.mfr_part_number,
      attrs.price_group,
      attrs.units_per_sku && `${attrs.units_per_sku} per SKU`,
      attrs.barcode,
    ].filter(Boolean).map(t => t.trim());
    console.log(`🏷️  [TAGS] Total product tags: ${productTags.length} — ${productTags.slice(0, 10).join(', ')}${productTags.length > 10 ? '...' : ''}`);

    // ── STEP 3: Media ────────────────────────────────────────────────────────
    const mediaInputs = (attrs.files || [])
      .filter(f => f.type === 'Image' && f.url)
      .map(file => ({
        originalSource: file.url,
        mediaContentType: 'IMAGE',
        alt: `${attrs.product_name} — ${file.media_content}`,
      }));
    console.log(`🖼️  [MEDIA] Image inputs: ${mediaInputs.length}`);
    if (mediaInputs.length > 0) {
      console.log(`🖼️  [MEDIA] First image URL: ${mediaInputs[0].originalSource}`);
    }

    // ── STEP 4: Description ──────────────────────────────────────────────────
    const marketDescs = (attrs.descriptions || [])
      .filter(d => d.type === 'Market Description')
      .map(d => d.description);
    const descriptionHtml = marketDescs.length
      ? marketDescs.reduce((a, b) => (b.length > a.length ? b : a))
      : attrs.part_description;
    console.log(`📝 [DESC] Market descriptions found: ${marketDescs.length}`);
    console.log(`📝 [DESC] Description length: ${(descriptionHtml || '').length} chars`);

    const handle = slugify(item.id);
    console.log(`🔗 [HANDLE] Generated handle: "${handle}"`);

    // ── STEP 5: Dedup check ──────────────────────────────────────────────────
    console.log(`🔍 [DEDUP] Checking if handle "${handle}" already exists in Shopify...`);
    const searchRes = await client.post('', {
      query: `query { products(first: 1, query: "handle:${handle}") { nodes { id handle } } }`
    });
    const exists = searchRes.data?.data?.products?.nodes?.length > 0;
    if (exists) {
      const existingId = searchRes.data.data.products.nodes[0].id;
      console.log(`🔍 [DEDUP] ⚠️  DUPLICATE — handle "${handle}" exists as ${existingId} — SKIPPING`);
      appendJobLog(jobId, `[SKIP] ${attrs.part_number} — handle "${handle}" already exists`);
      return { action: 'skipped', handle, product: attrs.product_name || attrs.part_number };
    }
    console.log(`🔍 [DEDUP] ✅ No duplicate found — proceeding to create`);

    // ── STEP 6: Create product ───────────────────────────────────────────────
    console.log(`🆕 [CREATE] Creating product in Shopify...`);
    console.log(`🆕 [CREATE] Title: "${attrs.product_name}"`);
    console.log(`🆕 [CREATE] Vendor: "${attrs.brand}"`);
    console.log(`🆕 [CREATE] Product type: "${attrs.category}"`);
    console.log(`🆕 [CREATE] Collections to join: ${collectionIds.length}`);
    console.log(`🆕 [CREATE] Media: ${mediaInputs.length} images`);

    const createProdRes = await client.post('', {
      query: `
        mutation ProductCreate($product: ProductCreateInput!, $media: [CreateMediaInput!]) {
          productCreate(product: $product, media: $media) {
            product {
              id
              variants(first: 1) { nodes { id inventoryItem { id } price compareAtPrice barcode } }
            }
            userErrors { field message }
          }
        }
      `,
      variables: {
        product: {
          title: attrs.product_name,
          descriptionHtml: descriptionHtml,
          vendor: attrs.brand,
          productType: attrs.category,
          handle,
          tags: productTags,
          collectionsToJoin: collectionIds,
          status: 'ACTIVE',
        },
        media: mediaInputs,
      },
    });

    const prodErrs = createProdRes.data.data?.productCreate?.userErrors || [];
    if (prodErrs.length) {
      console.error(`🆕 [CREATE] ❌ productCreate userErrors: ${JSON.stringify(prodErrs)}`);
      const taken = prodErrs.some(e => /already in use/i.test(e.message));
      if (taken) {
        console.log(`🆕 [CREATE] ⚠️  Duplicate handle — SKIPPING`);
        appendJobLog(jobId, `[SKIP] ${attrs.part_number} — duplicate handle`);
        return { action: 'skipped', handle, product: attrs.product_name || attrs.part_number };
      }
      throw new Error(`ProductCreate errors: ${prodErrs.map(e => e.message).join(', ')}`);
    }

    const createdProduct = createProdRes.data.data.productCreate.product;
    const variantNode = createdProduct.variants?.nodes?.[0];
    console.log(`🆕 [CREATE] ✅ Product created! Shopify Product ID: ${createdProduct.id}`);
    console.log(`🆕 [CREATE] Variant ID: ${variantNode?.id || 'NOT FOUND'}`);
    console.log(`🆕 [CREATE] Inventory Item ID: ${variantNode?.inventoryItem?.id || 'NOT FOUND'}`);

    if (!variantNode) {
      console.error(`🆕 [CREATE] ❌ No variant node returned — cannot continue`);
      return null;
    }

    const variantId = variantNode.id;
    const inventoryItemId = variantNode.inventoryItem?.id;

    // ── STEP 7: Pricing ──────────────────────────────────────────────────────
    console.log(`💰 [PRICING] Reading pricing config from Shopify metafield...`);
    const pricingConfigRes = await client.post('', {
      query: `query { shop { metafield(namespace: "turn14", key: "pricing_config") { value } } }`
    });
    let priceType = 'map';
    let percentage = 0;
    const pricingMf = pricingConfigRes.data?.data?.shop?.metafield;
    if (pricingMf?.value) {
      try {
        const p = JSON.parse(pricingMf.value);
        priceType = p.priceType || 'map';
        percentage = Number(p.percentage) || 0;
        console.log(`💰 [PRICING] Config found — priceType: "${priceType}", percentage: ${percentage}%`);
      } catch (e) {
        console.warn(`💰 [PRICING] Failed to parse pricing config JSON: ${e.message}`);
      }
    } else {
      console.log(`💰 [PRICING] No pricing config metafield found — using defaults (MAP, 0%)`);
    }

    const baseprice = parseFloat(attrs.price) || 0;
    let price = baseprice;
    if (priceType === 'percentage') price = baseprice + (baseprice * (percentage / 100));

    const comparePrice = parseFloat(attrs.compare_price) || null;
    const barcode = attrs.barcode || '';
    const weightValue = parseFloat(attrs.dimensions?.[0]?.weight) || 0;

    console.log(`💰 [PRICING] Base MAP price: $${baseprice}`);
    console.log(`💰 [PRICING] Final price: $${price.toFixed(2)} (${priceType === 'percentage' ? `${percentage}% markup` : 'MAP as-is'})`);
    console.log(`💰 [PRICING] Compare at price: ${comparePrice ? `$${comparePrice}` : 'not set'}`);
    console.log(`💰 [PRICING] Purchase cost: $${attrs.purchase_cost || 0}`);
    console.log(`💰 [PRICING] Barcode: "${barcode || 'none'}"`);
    console.log(`💰 [PRICING] Weight: ${weightValue} lbs`);

    // ── STEP 8: Variant update ───────────────────────────────────────────────
    console.log(`🔧 [VARIANT] Updating variant — SKU: "${attrs.part_number}", price: $${price.toFixed(2)}`);
    const bulkRes = await client.post('', {
      query: `
        mutation UpdateProductVariant($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
          productVariantsBulkUpdate(productId: $productId, variants: $variants) {
            productVariants { id price compareAtPrice barcode inventoryItem { sku measurement { weight { value unit } } tracked } }
            userErrors { field message }
          }
        }
      `,
      variables: {
        productId: createdProduct.id,
        variants: [{
          id: variantId,
          price,
          ...(comparePrice !== null && { compareAtPrice: comparePrice }),
          ...(barcode && { barcode }),
          inventoryItem: { sku: attrs.part_number, measurement: { weight: { value: weightValue, unit: 'POUNDS' } } },
        }],
      },
    });
    const bulkErrs = bulkRes.data.data.productVariantsBulkUpdate.userErrors;
    if (bulkErrs.length) {
      console.error(`🔧 [VARIANT] ❌ Bulk update errors: ${JSON.stringify(bulkErrs)}`);
      throw new Error(`Bulk update errors: ${bulkErrs.map(e => e.message).join(', ')}`);
    }
    const updatedVariant = bulkRes.data.data.productVariantsBulkUpdate.productVariants?.[0];
    console.log(`🔧 [VARIANT] ✅ Variant updated — price: $${updatedVariant?.price}, SKU: ${updatedVariant?.inventoryItem?.sku}`);

    // ── STEP 9: Publish ──────────────────────────────────────────────────────
    console.log(`📢 [PUBLISH] Fetching publications...`);
    const publicationsRes = await client.post('', {
      query: `query { publications(first: 10) { edges { node { id name } } } }`
    });
    const allPubs = publicationsRes.data.data.publications.edges;
    console.log(`📢 [PUBLISH] Available publications: ${allPubs.map(p => p.node.name).join(', ')}`);

    const onlineStorePub = allPubs.find(p => p.node.name === 'Online Store');
    if (onlineStorePub) {
      console.log(`📢 [PUBLISH] Publishing to Online Store (pub ID: ${onlineStorePub.node.id})...`);
      const publishRes = await client.post('', {
        query: `mutation($id: ID!, $publicationId: ID!) { publishablePublish(id: $id, input: { publicationId: $publicationId }) { publishable { ... on Product { id } } userErrors { field message } } }`,
        variables: { id: createdProduct.id, publicationId: onlineStorePub.node.id },
      });
      const publishErrs = publishRes.data.data.publishablePublish.userErrors;
      if (publishErrs.length) {
        console.error(`📢 [PUBLISH] ❌ Publish errors: ${JSON.stringify(publishErrs)}`);
        throw new Error(`Publish errors: ${publishErrs.map(e => e.message).join(', ')}`);
      }
      console.log(`📢 [PUBLISH] ✅ Published to Online Store`);
    } else {
      console.warn(`📢 [PUBLISH] ⚠️  "Online Store" publication not found — product not published`);
    }

    // ── STEP 10: Inventory cost ──────────────────────────────────────────────
    console.log(`📦 [INVENTORY] Updating inventory item — cost: $${parseFloat(attrs.purchase_cost) || 0}, tracked: true`);
    const invRes = await client.post('', {
      query: `
        mutation InventoryItemUpdate($id: ID!, $input: InventoryItemInput!) {
          inventoryItemUpdate(id: $id, input: $input) {
            inventoryItem { id sku unitCost { amount currencyCode } tracked }
            userErrors { field message }
          }
        }
      `,
      variables: { id: inventoryItemId, input: { cost: parseFloat(attrs.purchase_cost) || 0, tracked: true } },
    });
    const invErrs = invRes.data.data.inventoryItemUpdate.userErrors;
    if (invErrs.length) {
      console.error(`📦 [INVENTORY] ❌ inventoryItemUpdate errors: ${JSON.stringify(invErrs)}`);
      throw new Error(`Inventory update errors: ${invErrs.map(e => e.message).join(', ')}`);
    }
    const invItem = invRes.data.data.inventoryItemUpdate.inventoryItem;
    console.log(`📦 [INVENTORY] ✅ Cost set to $${invItem?.unitCost?.amount || 0} ${invItem?.unitCost?.currencyCode || 'USD'}, tracked: ${invItem?.tracked}`);

    // ── STEP 11: Activate inventory at location ──────────────────────────────
    if (locationId) {
      console.log(`📍 [INVENTORY-LOC] Activating inventory at location: ${locationId}`);
      await client.post('', {
        query: `mutation ActivateInventoryItem($inventoryItemId: ID!, $locationId: ID!) { inventoryActivate(inventoryItemId: $inventoryItemId, locationId: $locationId) { inventoryLevel { id } userErrors { field message } } }`,
        variables: { inventoryItemId, locationId },
      });
      console.log(`📍 [INVENTORY-LOC] ✅ Inventory activated at location`);

      // ── STEP 12: Set quantity ────────────────────────────────────────────
      console.log(`📍 [INVENTORY-QTY] Setting quantity to ${totalQuantity} at location ${locationId}`);
      await client.post('', {
        query: `
          mutation InventorySet($input: InventorySetQuantitiesInput!) {
            inventorySetQuantities(input: $input) {
              inventoryAdjustmentGroup { createdAt reason }
              userErrors { field message }
            }
          }
        `,
        variables: {
          input: {
            name: 'available',
            reason: 'correction',
            referenceDocumentUri: 'logistics://turn14.data4autos.com/inventory',
            ignoreCompareQuantity: true,
            quantities: [{ inventoryItemId, locationId, quantity: totalQuantity, compareQuantity: 1 }],
          },
        },
      });
      console.log(`📍 [INVENTORY-QTY] ✅ Quantity set to ${totalQuantity}`);
    } else {
      console.warn(`📍 [INVENTORY-LOC] ⚠️  No locationId on token record — inventory NOT activated or set`);
    }

    // ── STEP 13: SEO ─────────────────────────────────────────────────────────
    const finalSeoTitle = seo_title || `${attrs.product_name} | Auto Parts`;
    const finalSeoDesc = seo_description || `Find high-quality ${attrs.product_name} built for reliability and performance.`;
    console.log(`🔍 [SEO] Setting SEO title: "${finalSeoTitle}"`);
    console.log(`🔍 [SEO] Setting SEO description (${finalSeoDesc.length} chars)`);
    await client.post('', {
      query: `
        mutation ProductUpdate($product: ProductUpdateInput!) {
          productUpdate(product: $product) {
            product { id seo { title description } }
            userErrors { field message }
          }
        }
      `,
      variables: {
        product: {
          id: createdProduct.id,
          seo: {
            title: finalSeoTitle,
            description: finalSeoDesc,
          },
        },
      },
    });
    console.log(`🔍 [SEO] ✅ SEO fields updated`);

    console.log(`✅ [PRODUCT-DONE] ============================================`);
    console.log(`✅ [PRODUCT-DONE] SUCCESS: "${productLabel}"`);
    console.log(`✅ [PRODUCT-DONE] Shopify ID: ${createdProduct.id}`);
    console.log(`✅ [PRODUCT-DONE] Handle: ${handle}`);
    console.log(`✅ [PRODUCT-DONE] Part#: ${attrs.part_number}`);
    console.log(`✅ [PRODUCT-DONE] Price: $${price.toFixed(2)}`);
    console.log(`✅ [PRODUCT-DONE] Qty: ${totalQuantity}`);
    console.log(`✅ [PRODUCT-DONE] ============================================\n`);

    appendJobLog(jobId, `[PRODUCT-OK] Created: ${attrs.product_name} (${attrs.part_number})`);
    return { action: 'created', productId: createdProduct.id, handle, product: attrs.product_name };

  } catch (err) {
    console.error(`❌ [PRODUCT-FAIL] ============================================`);
    console.error(`❌ [PRODUCT-FAIL] FAILED: "${productLabel}"`);
    console.error(`❌ [PRODUCT-FAIL] Part#: ${attrs.part_number || 'N/A'}`);
    console.error(`❌ [PRODUCT-FAIL] Error: ${err.message}`);
    console.error(`❌ [PRODUCT-FAIL] Stack: ${err.stack}`);
    console.error(`❌ [PRODUCT-FAIL] ============================================\n`);
    appendJobLog(jobId, `[PRODUCT-FAIL] ${attrs.product_name || attrs.part_number}: ${err.message}`);
    return { action: 'failed', product: attrs.product_name || attrs.part_number, error: err.message };
  }
};

// ---------------------------------------------------------------------------
// POST /manageproducts — start import job
// ---------------------------------------------------------------------------
router.post('/', async (req, res) => {
  const { shop, brandID, brandName, turn14accessToken, productCount, selectedProductIds } = req.body;

  console.log(`\n🚀 [JOB-REQUEST] ================================================`);
  console.log(`🚀 [JOB-REQUEST] POST /manageproducts received`);
  console.log(`🚀 [JOB-REQUEST] Shop: ${shop}`);
  console.log(`🚀 [JOB-REQUEST] Brand ID: ${brandID}`);
  console.log(`🚀 [JOB-REQUEST] Brand Name: ${brandName}`);
  console.log(`🚀 [JOB-REQUEST] Selected product IDs count: ${Array.isArray(selectedProductIds) ? selectedProductIds.length : 'NOT ARRAY'}`);
  console.log(`🚀 [JOB-REQUEST] Selected IDs: ${JSON.stringify(selectedProductIds?.slice(0, 10))}${selectedProductIds?.length > 10 ? `... (+${selectedProductIds.length - 10} more)` : ''}`);
  console.log(`🚀 [JOB-REQUEST] Turn14 token (first 20): ${turn14accessToken?.slice(0, 20)}...`);
  console.log(`🚀 [JOB-REQUEST] ================================================\n`);

  if (!shop) return res.status(400).json({ error: 'Missing shop' });
  if (!turn14accessToken) return res.status(400).json({ error: 'Missing turn14accessToken' });
  if (!brandID) return res.status(400).json({ error: 'Missing brandID' });
  if (!Array.isArray(selectedProductIds) || selectedProductIds.length === 0) {
    return res.status(400).json({ error: 'selectedProductIds must be a non-empty array' });
  }

  const job = createJob({
    shop,
    brandId: brandID,
    brandName: brandName || `Brand ${brandID}`,
    totalSelected: selectedProductIds.length,
  });

  console.log(`🆔 [JOB-CREATED] Job ID: ${job.id}`);
  console.log(`🆔 [JOB-CREATED] Brand: ${brandName || brandID}`);
  console.log(`🆔 [JOB-CREATED] Total to import: ${selectedProductIds.length}`);

  log(shop, `[JOB] Created job ${job.id} for brand ${brandID} — ${selectedProductIds.length} products selected`);

  res.json({ processId: job.id, jobId: job.id, status: 'started' });

  // Run async — do not await
  (async () => {
    try {
      console.log(`\n⚙️  [JOB-RUN] ====================================================`);
      console.log(`⚙️  [JOB-RUN] Starting async import for job ${job.id}`);

      updateJob(job.id, { status: 'fetching_products', step: 'fetching_products', detail: `Fetching products for brand ${brandName || brandID} from Turn14...` });

      // ── Get Shopify token for this shop ──────────────────────────────────
      console.log(`🔑 [JOB-TOKEN] Looking up Shopify token for shop: ${shop}`);
      const tokenRecord = getToken(shop);
      if (!tokenRecord) {
        console.error(`🔑 [JOB-TOKEN] ❌ No token found for shop "${shop}" in tokens.json`);
        throw new Error('No token stored for shop — re-authenticate');
      }
      console.log(`🔑 [JOB-TOKEN] ✅ Token found`);
      console.log(`🔑 [JOB-TOKEN] Token (first 20): ${tokenRecord.accessToken?.slice(0, 20)}...`);
      console.log(`🔑 [JOB-TOKEN] Scope: ${tokenRecord.scope || 'N/A'}`);
      console.log(`🔑 [JOB-TOKEN] Saved at: ${tokenRecord.savedAt || 'N/A'}`);
      console.log(`🔑 [JOB-TOKEN] Location ID: ${tokenRecord.locationId || 'NOT SET ⚠️'}`);
      console.log(`🔑 [JOB-TOKEN] Fulfillment Service: ${tokenRecord.fulfillmentService ? JSON.stringify(tokenRecord.fulfillmentService).slice(0, 80) : 'NOT SET'}`);

      const locationId = tokenRecord.locationId || null;
      const accessToken = tokenRecord.accessToken;

      if (!locationId) {
        console.warn(`⚠️  [JOB-TOKEN] locationId is NULL — inventory will NOT be set for products`);
      }

      // ── Step 1: Fetch products from Turn14 ───────────────────────────────
      console.log(`\n📦 [JOB-STEP-1] Fetching all products for brand ${brandID} from Turn14...`);
      const products_res = await GetAllProductsOfBranch(brandID, turn14accessToken, shop, job.id);
      if (!products_res) {
        console.error(`❌ [JOB-STEP-1] Turn14 fetch returned null — aborting job`);
        throw new Error(`Failed to fetch products from Turn14 for brand ${brandID}`);
      }

      const allItems = products_res.items;
      console.log(`📦 [JOB-STEP-1] Total items from Turn14: ${allItems.length}`);

      // ── Step 2: Filter to selected IDs ───────────────────────────────────
      console.log(`\n🔽 [JOB-STEP-2] Filtering to selected ${selectedProductIds.length} product IDs...`);
      const products = allItems.filter(item => selectedProductIds.includes(item.id));
      const total = products.length;
      console.log(`🔽 [JOB-STEP-2] Matched ${total} out of ${allItems.length} Turn14 items`);

      if (total === 0) {
        console.warn(`⚠️  [JOB-STEP-2] No matching products found! Check if selected IDs exist in brand ${brandID}`);
        console.warn(`⚠️  [JOB-STEP-2] Selected IDs: ${JSON.stringify(selectedProductIds)}`);
        console.warn(`⚠️  [JOB-STEP-2] Available IDs (first 10): ${allItems.slice(0, 10).map(i => i.id).join(', ')}`);
      }

      updateJob(job.id, {
        status: 'importing',
        step: 'importing',
        detail: `Starting import of ${total} products...`,
        liveStats: { total, processed: 0, created: 0, skipped: 0, failed: 0, remaining: total, successRate: 0, label: `0/${total}` },
      });
      appendJobLog(job.id, `[IMPORT-START] Importing ${total} products for brand ${brandName || brandID}`);

      console.log(`\n🏁 [JOB-STEP-3] Starting product-by-product import (${total} products)...`);
      console.log(`⚙️  [JOB-STEP-3] ====================================================\n`);

      let created = 0, skipped = 0, failed = 0;

      for (let i = 0; i < products.length; i++) {
        if (isJobCancelled(job.id)) {
          console.log(`🛑 [JOB-CANCEL] Job ${job.id} cancelled at product ${i + 1}/${total}`);
          appendJobLog(job.id, '[CANCEL] Import cancelled by user');
          finishJob(job.id, 'cancelled');
          return;
        }

        const item = products[i];
        const attrs = item.attributes;
        const productLabel = attrs.product_name || attrs.part_number || `Item ${item.id}`;
        const partNum = attrs.part_number || '';

        console.log(`\n📋 [PRODUCT-LOOP] ─────────────────────────────────────────`);
        console.log(`📋 [PRODUCT-LOOP] Product ${i + 1} of ${total}`);
        console.log(`📋 [PRODUCT-LOOP] Name: ${productLabel}`);
        console.log(`📋 [PRODUCT-LOOP] Part#: ${partNum}`);
        console.log(`📋 [PRODUCT-LOOP] Turn14 ID: ${item.id}`);
        console.log(`📋 [PRODUCT-LOOP] Running totals → created:${created} skipped:${skipped} failed:${failed}`);

        updateJob(job.id, {
          currentProduct: { name: productLabel, partNumber: partNum, number: i + 1, total },
          detail: `Importing product ${i + 1}/${total}: ${productLabel}`,
        });
        appendJobLog(job.id, `[PRODUCT] (${i + 1}/${total}) ${productLabel}`);

        const result = await AddProductToStore(shop, accessToken, item, job.id, locationId);

        if (result?.action === 'created') {
          created++;
          console.log(`📋 [PRODUCT-LOOP] ✅ CREATED — total created so far: ${created}`);
        } else if (result?.action === 'skipped') {
          skipped++;
          console.log(`📋 [PRODUCT-LOOP] ⏭️  SKIPPED — total skipped so far: ${skipped}`);
        } else if (result?.action === 'failed') {
          failed++;
          console.error(`📋 [PRODUCT-LOOP] ❌ FAILED (${result?.error}) — total failed so far: ${failed}`);
          recordProductError(job.id, { index: i + 1, product: productLabel, error: result?.error || 'unknown error' });
        } else {
          console.warn(`📋 [PRODUCT-LOOP] ⚠️  NULL result returned for ${productLabel}`);
          failed++;
        }

        if (result) recordProductResult(job.id, result);

        const processed = i + 1;
        const successRate = processed > 0 ? Number((((processed - failed) / processed) * 100).toFixed(1)) : 0;

        console.log(`📋 [PRODUCT-LOOP] Progress: ${processed}/${total} (${successRate}% success rate)`);

        updateJob(job.id, {
          liveStats: { total, processed, created, skipped, failed, remaining: total - processed, successRate, label: `${processed}/${total}` },
        });

        if (processed % 5 === 0 || processed === total) {
          appendJobLog(job.id, `[STATS] total=${total} processed=${processed} created=${created} skipped=${skipped} failed=${failed} rate=${successRate}`);
        }
      }

      updateJob(job.id, { currentProduct: null });
      appendJobLog(job.id, `[IMPORT-DONE] Finished: ${created} created, ${skipped} skipped, ${failed} failed`);
      finishJob(job.id, 'done');

      console.log(`\n🎉 [JOB-DONE] ====================================================`);
      console.log(`🎉 [JOB-DONE] Job ${job.id} COMPLETED`);
      console.log(`🎉 [JOB-DONE] Shop: ${shop}`);
      console.log(`🎉 [JOB-DONE] Brand: ${brandName || brandID}`);
      console.log(`🎉 [JOB-DONE] Total selected: ${total}`);
      console.log(`🎉 [JOB-DONE] ✅ Created: ${created}`);
      console.log(`🎉 [JOB-DONE] ⏭️  Skipped: ${skipped}`);
      console.log(`🎉 [JOB-DONE] ❌ Failed:  ${failed}`);
      console.log(`🎉 [JOB-DONE] Success rate: ${total > 0 ? ((created / total) * 100).toFixed(1) : 0}%`);
      console.log(`🎉 [JOB-DONE] ====================================================\n`);

      log(shop, `[JOB] ${job.id} completed — created=${created} skipped=${skipped} failed=${failed}`);

    } catch (err) {
      console.error(`\n💥 [JOB-ERROR] ====================================================`);
      console.error(`💥 [JOB-ERROR] Job ${job.id} CRASHED`);
      console.error(`💥 [JOB-ERROR] Shop: ${shop}`);
      console.error(`💥 [JOB-ERROR] Error: ${err.message}`);
      console.error(`💥 [JOB-ERROR] Stack: ${err.stack}`);
      console.error(`💥 [JOB-ERROR] ====================================================\n`);
      appendJobLog(job.id, `[ERROR] ${err.message}`);
      updateJob(job.id, { status: 'error', step: 'error', detail: err.message, currentProduct: null });
      finishJob(job.id, 'error');
      log(shop, `[JOB] ${job.id} error — ${err.message}`);
    }
  })();
});

// ---------------------------------------------------------------------------
// GET /manageproducts/status/:processId — poll job status (legacy + new)
// ---------------------------------------------------------------------------
router.get('/status/:processId', (req, res) => {
  const job = getJob(req.params.processId);
  if (!job) return res.status(404).json({ error: 'Job not found' });

  const s = job.liveStats;

  res.json({
    status: job.status,
    detail: job.detail,
    progress: s.total > 0 ? Math.round((s.processed / s.total) * 100) : 0,
    current: job.currentProduct,
    stats: { total: s.total, processed: s.processed, remaining: s.remaining },
    results: job.results,
    job,
  });
});

// ---------------------------------------------------------------------------
// GET /manageproducts/jobs — list all jobs (optionally ?shop=...)
// ---------------------------------------------------------------------------
router.get('/jobs', (req, res) => {
  const shop = req.query.shop || null;
  res.json({ jobs: listJobs(shop) });
});

// ---------------------------------------------------------------------------
// GET /manageproducts/jobs/:jobId — get single job
// ---------------------------------------------------------------------------
router.get('/jobs/:jobId', (req, res) => {
  const job = getJob(req.params.jobId);
  if (!job) return res.status(404).json({ error: 'Job not found' });
  res.json(job);
});

// ---------------------------------------------------------------------------
// POST /manageproducts/jobs/:jobId/cancel
// ---------------------------------------------------------------------------
router.post('/jobs/:jobId/cancel', (req, res) => {
  const job = cancelJob(req.params.jobId);
  if (!job) return res.status(404).json({ error: 'Job not found' });
  res.json({ ok: true, job });
});

module.exports = router;
