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

const router = express.Router();
const API_VERSION = '2023-10';
// Simple in-memory process tracker
const processes = {};

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

const GetAllProductsOfBranch = async (brandId, turn14accessToken, shop, procId) => {
  var AllProductsOfBrans = [];

  try {
    log(shop, `🔍 [${procId}] Fetching products for brand ${brandId}`);
    const res = await fetch(`https://turn14.data4autos.com/v1/items/brandallitems/${brandId}`, {
      headers: {
        Authorization: `Bearer ${turn14accessToken}`,
        "Content-Type": "application/json",
      },
    });
    const data = await res.json();
    // Ensure we have an array of valid items
    const validItems = Array.isArray(data)
      ? data.filter(item => item && item.id && item.attributes)
      : [];
    AllProductsOfBrans = validItems;
    log(shop, `📦 [${procId}] Found ${AllProductsOfBrans.length} products for brand ${brandId}`);

    const items = Array.isArray(AllProductsOfBrans) ? AllProductsOfBrans.slice(0, 1) : [];
    // const items = Array.isArray(AllProductsOfBrans) ? AllProductsOfBrans : [];
    log(shop, `📝 [${procId}] Processing ${items.length} sample products`);

    return items;
  } catch (err) {
    log(shop, `❌ [${procId}] Error fetching items: ${err.message}`);
    return null;
  }
}

const AddProductToStore = async (shop, accessToken, product, procId) => {
  var results = [];
  const SHOP = shop;
  const ACCESS_TOKEN = accessToken;
  const item = product;

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

    log(shop, `🛒 [${procId}] Processing product: ${attrs.product_name || attrs.part_number}`);

    // Build and normalize collection titles
    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].filter(Boolean))
    );

    // Find or create collections, collect their IDs
    const collectionIds = [];

    for (const title of collectionTitles) {
      log(shop, `🏷️ [${procId}] Handling collection: ${title}`);

      // 1. Query existing manual collection by title
      const lookupQuery = `
        query {
          collections(first: 1, query: "title:\\"${title}\\" AND collection_type:manual") {
            nodes { id }
          }
        }
      `;
      const lookupResp = await client.post('', { query: lookupQuery });
      const existing = lookupResp.data.data.collections.nodes;

      if (existing.length) {
        log(shop, `✅ [${procId}] Found existing collection: ${title}`);
        collectionIds.push(existing[0].id);
        continue;
      }

      // 2. Otherwise, create it
      log(shop, `➕ [${procId}] Creating new collection: ${title}`);
      const createMutation = `
        mutation collectionCreate($input: CollectionInput!) {
          collectionCreate(input: $input) {
            collection { id }
            userErrors { field message }
          }
        }
      `;
      const createResp = await client.post('', {
        query: createMutation,
        variables: { input: { title } }
      });
      const createData = createResp.data.data.collectionCreate;
      if (createData.userErrors.length) {
        throw new Error(
          `Could not create collection "${title}": ` +
          createData.userErrors.map(e => e.message).join(', ')
        );
      }
      const newId = createData.collection.id;
      log(shop, `✨ [${procId}] Created collection: ${title} (ID: ${newId})`);
      collectionIds.push(newId);
    }

    // Build tags
    const tags = [
      attrs.category,
      ...subcats,
      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());

    // Prepare media inputs
    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}`,
      }));

    // Pick the longest "Market Description" or fallback to part_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;

    log(shop, `🔄 [${procId}] Creating product: ${attrs.product_name}`);
    const createProdRes = await client.post('', {
      query: `
        mutation($prod: ProductInput!, $media: [CreateMediaInput!]) {
          productCreate(input: $prod, media: $media) {
            product {
              id
              variants(first: 1) {
                nodes {
                  id
                  inventoryItem { id }
                  price
                  compareAtPrice
                  barcode
                }
              }
            }
            userErrors { field message }
          }
        }
      `,
      variables: {
        prod: {
          title: attrs.product_name,
          descriptionHtml: descriptionHtml,
          vendor: attrs.brand,
          productType: attrs.category,
          handle: slugify(item.id + "-" + (attrs.mfr_part_number || attrs.product_name)),
          tags,
          collectionsToJoin: collectionIds,
          status: "ACTIVE",
        },
        media: mediaInputs,
      },
    });

    const createProdJson = createProdRes.data;
    const prodErrs = createProdJson.data?.productCreate?.userErrors || [];
    if (prodErrs.length) {
      const taken = prodErrs.some(e => /already in use/i.test(e.message));
      if (taken) {
        log(shop, `⏭️ [${procId}] Skipping duplicate product: ${attrs.part_number}`);
        results.push({ skippedHandle: attrs.part_number, reason: "handle in use" });
        return null;
      }
      throw new Error(`ProductCreate errors: ${prodErrs.map(e => e.message).join(", ")}`);
    }

    const product = createProdJson.data.productCreate.product;
    const variantNode = product.variants?.nodes?.[0];
    if (!variantNode) {
      log(shop, `⚠️ [${procId}] No variant found for product: ${product.id}`);
      return null;
    }

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

    // Bulk-update variant (price, compare-at, barcode)
    const price = parseFloat(attrs.price) || 1000;
    const comparePrice = parseFloat(attrs.compare_price) || null;
    const barcode = attrs.barcode || "";

    log(shop, `💲 [${procId}] Updating pricing for variant: ${variantId}`);
    // const bulkRes = await client.post('', {
    //   query: `
    //     mutation($productId: ID!, $variants: [ProductVariantsBulkInput!]!) {
    //       productVariantsBulkUpdate(productId: $productId, variants: $variants) {
    //         productVariants {
    //           id
    //           price
    //           compareAtPrice
    //           barcode
    //         }
    //         userErrors {
    //           field
    //           message
    //         }
    //       }
    //     }
    //   `,
    //   variables: {
    //     productId: product.id,
    //     variants: [{
    //       id: variantId,
    //       price,
    //       ...(comparePrice !== null && { compareAtPrice: comparePrice }),
    //       ...(barcode && { barcode }),
    //     }],
    //   },
    // });




    const bulkRes = await client.post('', {
      query: `
    mutation UpdateProductVariant(
  $productId: ID!,
  $variants: [ProductVariantsBulkInput!]!
) {
  productVariantsBulkUpdate(productId: $productId, variants: $variants) {
    productVariants {
      id
      price
      compareAtPrice
      barcode
      sku
      inventoryItem {
        measurement {
          weight {
            value
            unit
          }
        }
        tracked
      }
    }
    userErrors {
      field
      message
    }
  }
}
      `,
      variables: {
        productId: product.id,
        variants: [{
          id: variantId,
          price,
          ...(comparePrice !== null && { compareAtPrice: comparePrice }),
          ...(barcode && { barcode }),
          sku: "SKU1",
          inventoryItem: {
            measurement: {
              weight: { value: 0.47, unit: "POUNDS" }
            },
            tracked: true
          }
        }]
      },
    });

    const bulkJson = bulkRes.data;
    if (bulkJson.errors) {
      console.error("GraphQL errors:", bulkJson.errors);
    }
    if (!bulkJson.data || !bulkJson.data.productVariantsBulkUpdate) {
      console.error("No productVariantsBulkUpdate in response:", bulkJson);
    } else {
      const bulkErrs = bulkJson.data.productVariantsBulkUpdate.userErrors;
      // process userErrors or productVariants as needed
      if (bulkErrs.length) {
        throw new Error(`Bulk update errors: ${bulkErrs.map(e => e.message).join(", ")}`);
      }
      log(shop, `✅ [${procId}] Updated variant ${variantId} with price ${price}, compare-at ${comparePrice}, barcode ${barcode}`);
    }
    const bulkErrs = bulkJson.data.productVariantsBulkUpdate.userErrors;
    if (bulkErrs.length) {
      throw new Error(`Bulk update errors: ${bulkErrs.map(e => e.message).join(", ")}`);
    }

    // Fetch the Online Store publication ID
    log(shop, `📢 [${procId}] Publishing product to Online Store`);
    const publicationsRes = await client.post('', {
      query: `
        query {
          publications(first: 10) {
            edges {
              node {
                id
                name
              }
            }
          }
        }
      `
    });
    const publicationsJson = publicationsRes.data;
    const onlineStorePublication = publicationsJson.data.publications.edges.find(
      pub => pub.node.name === 'Online Store'
    );
    const onlineStorePublicationId = onlineStorePublication ? onlineStorePublication.node.id : null;

    if (onlineStorePublicationId) {
      const publishRes = await client.post('', {
        query: `
          mutation($id: ID!, $publicationId: ID!) {
            publishablePublish(id: $id, input: { publicationId: $publicationId }) {
              publishable {
                ... on Product {
                  id
                  title
                  status
                }
              }
              userErrors { field message }
            }
          }
        `,
        variables: {
          id: product.id,
          publicationId: onlineStorePublicationId,
        },
      });

      const publishJson = publishRes.data;
      const publishErrs = publishJson.data.publishablePublish.userErrors;
      if (publishErrs.length) {
        throw new Error(`Publish errors: ${publishErrs.map(e => e.message).join(", ")}`);
      }
      log(shop, `🌐 [${procId}] Published product to Online Store`);
    } else {
      throw new Error("Online Store publication not found.");
    }

    const costPerItem = parseFloat(attrs.purchase_cost) || 0;
    const weightValue = parseFloat(attrs.dimensions?.[0]?.weight) || 0;

    console.log(`[${procId}] Updating inventory for product ${product.id} with cost ${costPerItem} and weight ${weightValue}`);

    log(shop, `📦 [${procId}] Updating inventory for product`);
    const invRes = await client.post('', {
      query: `
        mutation($id: ID!, $input: InventoryItemUpdateInput!) {
          inventoryItemUpdate(id: $id, input: $input) {
            inventoryItem {
              id
              sku
              unitCost { amount }
              tracked
              measurement {
                weight {
                  value
                  unit
                }
              }
            }
            userErrors { field message }
          }
        }
      `,
      variables: {
        id: inventoryItemId,
        input: {
          cost: parseFloat(attrs.purchase_cost) || 0,
          sku: attrs.part_number,
          measurement: {
            weight: { value: weightValue, unit: "POUNDS" }
          },
          // tracked: true
        }
      }
    });

    const invJson = invRes.data;
    const invErrs = invJson.data.inventoryItemUpdate.userErrors;
    if (invErrs.length) {
      throw new Error(`Inventory update errors: ${invErrs.map(e => e.message).join(", ")}`);
    }

    // Get the updated inventory item from the response
    const updatedInventoryItem = invJson.data.inventoryItemUpdate.inventoryItem;

    // Collect results
    results.push({
      productId: product.id,
      variant: {
        id: variantId,
        price: variantNode.price,
        compareAtPrice: variantNode.compareAtPrice,
        // sku: updatedInventoryItem.sku || attrs.part_number || '',
        // barcode: variantNode.barcode || attrs.barcode || '',
        // weight: updatedInventoryItem?.measurement?.weight?.value || 0,
        // weightUnit: updatedInventoryItem?.measurement?.weight?.unit || 'kg',
      },
      collections: collectionTitles,
      tags,
    });

    log(shop, `✅ [${procId}] Successfully processed product: ${attrs.product_name}`);
    return results;

  } catch (err) {
    log(shop, `❌ [${procId}] Error processing product: ${err.message}`);
    results.push({
      error: `Failed to process item ${item.id}: ${err.message}`,
      product: attrs.product_name || attrs.part_number || 'Unknown'
    });
    return results;
  }
}


const GetAllProductsandAddToStore = async (shop, accessToken, brandId, turn14accessToken, procId) => {
  log(shop, `🔍 [${procId}] Fetching products for brand ${brandId}`);
  const products = await GetAllProductsOfBranch(brandId, turn14accessToken, shop, procId);
  if (!products) {
    log(shop, `⚠️ [${procId}] No products found for brand ${brandId}`);
    return [];
  }

  // Update total products count
  processes[procId].totalProducts = products.length;
  processes[procId].processedProducts = 0;

  const results = [];
  log(shop, `🔄 [${procId}] Processing ${products.length} products`);

  for (const [index, item] of products.entries()) {
    try {
      // Update current product being processed
      const attrs = item.attributes;
      processes[procId].currentProduct = {
        name: attrs.product_name || attrs.part_number || 'Unknown',
        number: index + 1,
        total: products.length
      };
      processes[procId].status = `processing (${index + 1}/${products.length})`;

      const res = await AddProductToStore(shop, accessToken, item, procId);
      if (res) results.push(...res);

      // Update processed count
      processes[procId].processedProducts = index + 1;
      processes[procId].detail = `Processed ${index + 1} of ${products.length} products`;

    } catch (err) {
      log(shop, `⚠️ [${procId}] Error processing product ${index + 1}: ${err.message}`);
      results.push({
        error: `Failed to process product ${index + 1}: ${err.message}`,
        product: item.attributes.product_name || item.attributes.part_number || 'Unknown'
      });
    }
  }

  // Clear current product when done
  processes[procId].currentProduct = null;
  log(shop, `✅ [${procId}] Completed processing ${results.length} products`);
  return results;
}

router.post('/', async (req, res) => {
  const { shop, brandID, turn14accessToken } = req.body;

  const procId = uuid();
  processes[procId] = {
    status: 'started',
    detail: null,
    totalProducts: 0,
    processedProducts: 0,
    currentProduct: null,
    results: []
  };
  log(shop, `🔔 [${procId}] Starting product import for brand ${brandID}`);

  res.json({ processId: procId, status: 'started' });

  (async () => {
    try {
      processes[procId].status = 'fetching_products';
      log(shop, `🔍 [${procId}] Fetching token for shop`);

      // 1. Get token
      const tokenRecord = getToken(shop);
      if (!tokenRecord) throw new Error('No token for shop');

      processes[procId].status = 'importing_products';
      processes[procId].detail = 'Starting product import';

      const importResults = await GetAllProductsandAddToStore(shop, tokenRecord.accessToken, brandID, turn14accessToken, procId);

      log(shop, `✅ [${procId}] Successfully imported ${importResults.length} products`);
      processes[procId].status = 'done';
      processes[procId].detail = `Imported ${importResults.length} products`;
      processes[procId].results = importResults;

    } catch (err) {
      processes[procId].status = 'error';
      processes[procId].detail = err.message;
      log(shop, `❌ [${procId}] Error: ${err.message}`);
    }
  })();
});

router.get('/status/:processId', (req, res) => {
  const info = processes[req.params.processId];
  if (!info) return res.status(404).json({ error: 'Not found' });

  const response = {
    status: info.status,
    detail: info.detail,
    progress: info.totalProducts > 0
      ? Math.round((info.processedProducts / info.totalProducts) * 100)
      : 0,
    current: info.currentProduct,
    stats: {
      total: info.totalProducts,
      processed: info.processedProducts,
      remaining: info.totalProducts - info.processedProducts
    },
    results: info.results || []
  };

  res.json(response);
});
module.exports = router;