/**
 * shopify-bulk-inventory-with-logs.js
 *
 * Fully automated:
 *   1. start export
 *   2. poll until ready
 *   3. download NDJSON (saved as ./exports/YYYYMMDD_HHMMSS_bulk_export.ndjson)
 *   4. parse & map handles→inventory items (saved as ./exports/YYYYMMDD_HHMMSS_handle_map.json)
 *   5. fire off the bulk inventory update
 */

const axios = require('axios');
const https = require('https');
const fs = require('fs');
const readline = require('readline');
const path = require('path');

// ─── CONFIG ─────────────────────────────────────────────────────────────────────
const SHOP = 'veloxautomotive.myshopify.com';
const ACCESS_TOKEN = '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';
const API_VERSION = '2023-10';



const desiredInventoryByHandle = {};




// Ensure exports directory exists
const exportDir = path.join(__dirname, 'exports');
if (!fs.existsSync(exportDir)) {
    console.log('Creating exports directory at', exportDir);
    fs.mkdirSync(exportDir);
}

// ─── HELPERS ────────────────────────────────────────────────────────────────────
function timestamp() {
    const now = new Date();
    const yyyy = now.getFullYear();
    const MM = String(now.getMonth() + 1).padStart(2, '0');
    const dd = String(now.getDate()).padStart(2, '0');
    const hh = String(now.getHours()).padStart(2, '0');
    const mm = String(now.getMinutes()).padStart(2, '0');
    const ss = String(now.getSeconds()).padStart(2, '0');
    return `${yyyy}${MM}${dd}_${hh}${mm}${ss}`;
}

// ─── 1. START THE EXPORT ─────────────────────────────────────────────────────────
async function startBulkExport() {
    console.log('[1] Starting bulk export…');
    const mutation = `
  mutation {
  bulkOperationRunQuery(
    query: """
    {
      products {
        edges {
          node {
            id
            handle
            variants {
              edges {
                node {
                  id
                  inventoryItem { id }
                }
              }
            }
          }
        }
      }
    }
    """
  ) {
    bulkOperation { id status }
    userErrors { field message }
  }
}
  `;

    const resp = await axios.post(
        `https://${SHOP}/admin/api/${API_VERSION}/graphql.json`,
        { query: mutation },
        { headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN } }
    );

    const err = resp.data.data.bulkOperationRunQuery.userErrors;
    if (err.length) {
        console.error('[1] ❌ Errors starting export:', err);
        throw new Error('Error starting export');
    }

    console.log('[1] ✔️ Export kicked off:', resp.data.data.bulkOperationRunQuery.bulkOperation);
}

// ─── 2. POLL FOR COMPLETION ───────────────────────────────────────────────────────
async function pollUntilReady() {
    console.log('[2] Polling for bulk-export completion…');
    const query = `{
    currentBulkOperation {
      status
      url
      errorCode
    }
  }`;

    while (true) {
        const resp = await axios.post(
            `https://${SHOP}/admin/api/${API_VERSION}/graphql.json`,
            { query },
            { headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN } }
        );
        const op = resp.data.data.currentBulkOperation;
        console.log(`[2] Status: ${op.status}`);

        if (op.status === 'COMPLETED') {
            console.log('[2] ✔️ Completed. URL:', op.url);
            return op.url;
        }
        if (op.status === 'FAILED') {
            console.error('[2] ❌ Failed with code:', op.errorCode);
            throw new Error('Bulk operation failed');
        }

        // still in progress…
        await new Promise(r => setTimeout(r, 5000));
    }
}

// ─── 3. DOWNLOAD TO FILE ─────────────────────────────────────────────────────────
async function downloadToFile(fileUrl) {
    const fname = path.join(exportDir, `${timestamp()}_bulk_export.ndjson`);
    console.log('[3] Downloading export to', fname);

    const fileStream = fs.createWriteStream(fname);
    await new Promise((resolve, reject) => {
        https.get(fileUrl, res => {
            res.pipe(fileStream);
            fileStream.on('finish', () => {
                console.log('[3] ✔️ Download complete');
                fileStream.close(resolve);
            });
            fileStream.on('error', err => {
                console.error('[3] ❌ Download error:', err);
                reject(err);
            });
        });
    });

    return fname;
}

// ─── 4. PARSE & MAP HANDLES → INVENTORY ITEM IDS ─────────────────────────────────
async function buildHandleMap(ndjsonPath) {
    console.log('[4] Parsing NDJSON and building handle map…');
    const handleMap = {};
    let totalLines = 0;

    const rl = readline.createInterface({
        input: fs.createReadStream(ndjsonPath),
        crlfDelay: Infinity
    });

    for await (const line of rl) {
        totalLines++;
        try {
            const rec = JSON.parse(line);
            const h = rec.handle;
            if (desiredInventoryByHandle.hasOwnProperty(h)) {
                handleMap[h] = rec.variants.edges.map(v => ({
                    variantId: v.node.id,
                    inventoryItemId: v.node.inventoryItem.id
                }));
            }
        } catch (e) {
            console.error('[4] ⚠️ JSON parse error on line', totalLines, e);
        }
    }

    console.log(`[4] ✔️ Parsed ${totalLines} lines. Matched handles:`, Object.keys(handleMap));

    // also save the map to disk
    const mapPath = path.join(exportDir, `${timestamp()}_handle_map.json`);
    fs.writeFileSync(mapPath, JSON.stringify(handleMap, null, 2));
    console.log('[4] ✔️ Saved handle→inventory map to', mapPath);

    return handleMap;
}

// ─── 5. PREPARE & RUN BULK UPDATE MUTATION ────────────────────────────────────────
function makeBulkUpdateMutation(handleMap) {
    console.log('[5] Building bulk update mutation…');
    const ops = [];

    for (const [handle, items] of Object.entries(handleMap)) {
        const qty = desiredInventoryByHandle[handle];
        items.forEach(({ inventoryItemId }) => {
            ops.push(`
        inventoryAdjustQuantity(
          input: {inventoryItemId: "${inventoryItemId}", availableDelta: ${qty}}
        ) {
          inventoryLevel { id available }
          userErrors { field message }
        }
      `);
        });
    }

    const full = `
    mutation {
      bulkOperationRunMutation(
        mutation: """
        mutation {
          ${ops.join('\n')}
        }
        """
      ) {
        bulkOperation { id status }
        userErrors { field message }
      }
    }
  `;
    console.log('[5] ✔️ Mutation built with', ops.length, 'operations');
    return full;
}




async function fetchAllLocations(pageSize = 250) {
    const endpoint = `https://${SHOP}/admin/api/2023-10/graphql.json`;
    let hasNextPage = true;
    let cursor = null;
    const allLocations = [];

    while (hasNextPage) {
        const query = `
      query ($first: Int!, $after: String) {
        locations(first: $first, after: $after) {
          pageInfo {
            hasNextPage
          }
          edges {
            cursor
            node {
              id
              name
            }
          }
        }
      }
    `;
        const variables = { first: pageSize, after: cursor };
        console.log('Fetching locations page, after cursor:', cursor);

        const resp = await axios.post(
            endpoint,
            { query, variables },
            { headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN } }
        );

        const locs = resp.data.data.locations;
        locs.edges.forEach(edge => {
            allLocations.push(edge.node);
        });

        hasNextPage = locs.pageInfo.hasNextPage;
        cursor = hasNextPage ? locs.edges[locs.edges.length - 1].cursor : null;
    }

    console.log(allLocations)
    console.log(`✅ Retrieved ${allLocations.length} locations in total`);
    return allLocations;
}


// ─── MAIN FLOW ────────────────────────────────────────────────────────────────────
(async function main() {
    try {

        await fetchAllLocations(20)
        await startBulkExport();
        const url = await pollUntilReady();
        const ndjsonPath = await downloadToFile(url);
        const handleMap = await buildHandleMap(ndjsonPath);

        // Now fire off the inventory update
        const mutation = makeBulkUpdateMutation(handleMap);
        console.log('[5] Kicking off inventory update…');
        const resp = await axios.post(
            `https://${SHOP}/admin/api/${API_VERSION}/graphql.json`,
            { query: mutation },
            { headers: { 'X-Shopify-Access-Token': ACCESS_TOKEN } }
        );

        const errs = resp.data.data.bulkOperationRunMutation.userErrors;
        if (errs.length) {
            console.error('[5] ❌ Inventory bulk update errors:', errs);
        } else {
            console.log('[5] ✔️ Inventory bulk update kickstarted successfully');
        }
    } catch (err) {
        console.error('🚨 Uncaught error in automation:', err);
        process.exit(1);
    }
})();
