import refreshTokenHelper from "../../../utils/refreshTokenHelper"
import errorHandlingHelper from "../../../utils/errorHandlingHelper"
import fetchHelper from "../../../utils/fetchHelper"
import { getShopifyNewAccessToken, shopifyNewGraphQL, parseShopifyGid } from "../../../utils/shopifyNewAuthHelper"

// POST /api/shopify-new/stocks
// Body: { orderSourceId, variantIds (comma-separated or array), productIds (comma-separated "pid:key" or object) }
// Fetches current stock from Shopify via GraphQL Admin API v2025-10
// Returns same response shape as /api/shopify/stocks for frontend compatibility
// Uses POST to avoid URL length limits with large SKU lists
const handleFunc = async (event: any, authToken: any = null) => {
  const token = authToken ?? await getTokenHelper(event)
  const body = await readBody(event)
  const orderSourceId = body.orderSourceId as string
  const variantIdsParam = body.variantIds as string
  const productIdsParam = (body.productIds as string) || ''

  if(!orderSourceId) {
    return { status: 400, message: 'orderSourceId is required' }
  }
  if(!variantIdsParam) {
    return { status: 400, message: 'variantIds is required' }
  }

  const skus = variantIdsParam.split(',').map(id => id.trim()).filter(Boolean)
  if(skus.length === 0) {
    return { status: 400, message: 'No valid SKUs provided' }
  }

  // Parse productIds param: "shopifyProductId:localKey,shopifyProductId2:localKey2"
  // Maps Shopify product numeric ID -> local key (SKU) for fallback matching
  const productIdToLocalKey: Record<string, string> = {}
  if(productIdsParam) {
    for(const entry of productIdsParam.split(',')) {
      const colonIdx = entry.indexOf(':')
      if(colonIdx > 0) {
        const pid = entry.substring(0, colonIdx).trim()
        const localKey = entry.substring(colonIdx + 1).trim()
        if(pid && localKey) {
          productIdToLocalKey[pid] = localKey
        }
      }
    }
  }

  // Load order source to verify it's shopify-new and get credentials
  const os: any = await fetchHelper(event, `models/c_ordersource/${orderSourceId}`, 'GET', token, null)
  if(!os) {
    return { status: 404, message: 'Order Source not found' }
  }
  if(os?.Marketplace?.identifier !== 'shopify-new') {
    return { status: 400, message: 'Selected Order Source is not Shopify-New' }
  }

  try {
    const { accessToken, graphqlUrl } = await getShopifyNewAccessToken(os)

    const stocks: Record<string, number> = {}
    const inventoryItemIds: Record<string, string> = {}
    const errors: Record<string, string> = {}
    const skuSet = new Set(skus.map(s => s.toLowerCase()))

    // Initialize all requested SKUs with 0
    for(const sku of skus) {
      stocks[sku] = 0
    }

    // Step 1: Fetch all locations
    const locationsMap: Record<string, { id: string, name: string, active: boolean }> = {}
    try {
      const locationsQuery = `{
        locations(first: 50) {
          edges {
            node {
              id
              name
              isActive
            }
          }
        }
      }`
      const locRes = await shopifyNewGraphQL(graphqlUrl, accessToken, locationsQuery)
      const locationEdges = locRes?.data?.locations?.edges || []
      for(const edge of locationEdges) {
        const node = edge.node
        const numericId = parseShopifyGid(node.id)
        locationsMap[numericId] = {
          id: numericId,
          name: node.name || `Location ${numericId}`,
          active: node.isActive ?? true
        }
      }
      console.log(`shopify-new: Found ${Object.keys(locationsMap).length} locations`)
    } catch (locErr: any) {
      console.log('shopify-new: Could not fetch locations:', locErr?.message)
    }

    // Step 2: Look up variants by SKU in batches using GraphQL aliases
    // Each alias queries productVariants(first:1, query:"sku:...") with nested inventoryLevels
    // Batches of ~40 SKUs keep query cost under 1000 (each alias costs ~11 points: 1 + 1*10)
    const skuInventoryMap: Record<string, {
      inventoryItemGid: string,
      stockByLocation: Record<string, { qty: number, name: string }>,
      total: number
    }> = {}

    const BATCH_SIZE = 40
    const skuBatches: string[][] = []
    for(let i = 0; i < skus.length; i += BATCH_SIZE) {
      skuBatches.push(skus.slice(i, i + BATCH_SIZE))
    }

    console.log(`shopify-new: Looking up ${skus.length} SKUs in ${skuBatches.length} batch(es)`)

    // Fragment for variant fields to keep the query readable
    const variantFragment = `
      fragment VariantFields on ProductVariant {
        id
        sku
        inventoryItem {
          id
          inventoryLevels(first: 10) {
            edges {
              node {
                location { id name }
                quantities(names: "available") { quantity }
              }
            }
          }
        }
      }
    `

    for(let batchIdx = 0; batchIdx < skuBatches.length; batchIdx++) {
      const batch = skuBatches[batchIdx]

      try {
        // Build aliased query: each alias looks up one SKU
        const aliasQueries = batch.map((sku, idx) => {
          // Escape double quotes in SKU for the query string
          const escapedSku = sku.replace(/"/g, '\\"')
          return `v${idx}: productVariants(first: 1, query: "sku:\\"${escapedSku}\\"") {
            edges { node { ...VariantFields } }
          }`
        }).join('\n')

        const batchQuery = `${variantFragment}\n{ ${aliasQueries} }`

        console.log(`shopify-new: Batch ${batchIdx + 1}/${skuBatches.length} (${batch.length} SKUs)...`)
        const res = await shopifyNewGraphQL(graphqlUrl, accessToken, batchQuery)

        // Check rate limiting
        const available = res?.extensions?.cost?.throttleStatus?.currentlyAvailable
        if(available !== undefined && available < 100) {
          console.log(`shopify-new: Rate limit low (${available} points), sleeping 2s...`)
          await new Promise(resolve => setTimeout(resolve, 2000))
        }

        // Parse each alias response
        for(let idx = 0; idx < batch.length; idx++) {
          const sku = batch[idx]
          const aliasData = res?.data?.[`v${idx}`]
          const variantEdges = aliasData?.edges || []

          if(variantEdges.length === 0) continue

          const variant = variantEdges[0].node
          const variantSku = String(variant.sku || '').toLowerCase()
          const inventoryItem = variant.inventoryItem
          const inventoryItemGid = inventoryItem?.id || ''
          const levelEdges = inventoryItem?.inventoryLevels?.edges || []

          const stockByLocation: Record<string, { qty: number, name: string }> = {}
          let total = 0

          for(const levelEdge of levelEdges) {
            const level = levelEdge.node
            const locationGid = level.location?.id || ''
            const locationNumericId = parseShopifyGid(locationGid)
            const locationName = level.location?.name || locationsMap[locationNumericId]?.name || `Location ${locationNumericId}`
            const qty = Number(level.quantities?.[0]?.quantity ?? 0)

            stockByLocation[locationNumericId] = { qty, name: locationName }
            total += qty
          }

          // Use the original SKU case (as sent from frontend) for the key
          const mapKey = variantSku || sku.toLowerCase()
          skuInventoryMap[mapKey] = {
            inventoryItemGid,
            stockByLocation,
            total
          }
        }
      } catch (err: any) {
        console.error(`shopify-new: Batch ${batchIdx + 1} failed:`, err?.message || err)
      }
    }

    console.log(`shopify-new: Built SKU inventory map with ${Object.keys(skuInventoryMap).length} entries`)

    // Step 3: Map back to requested SKUs
    const stocksByLocation: Record<string, Record<string, { qty: number, name: string }>> = {}

    for(const sku of skus) {
      const skuLower = sku.toLowerCase()
      const mapping = skuInventoryMap[skuLower]
      if(mapping) {
        inventoryItemIds[sku] = mapping.inventoryItemGid
        stocks[sku] = mapping.total
        if(Object.keys(mapping.stockByLocation).length > 0) {
          stocksByLocation[sku] = mapping.stockByLocation
        }
      } else {
        errors[sku] = 'SKU not found in Shopify'
      }
    }

    return {
      status: 200,
      stocks,
      stocksByLocation,
      inventoryItemIds,
      locations: locationsMap,
      errors: Object.keys(errors).length > 0 ? errors : undefined,
      skuCount: skus.length,
      matchedCount: Object.keys(skuInventoryMap).length
    }

  } catch (err: any) {
    console.error('shopify-new stocks error:', err)
    const data = errorHandlingHelper(err?.data ?? err, err?.data ?? err)
    return {
      status: Number(data?.status || 500),
      message: data?.message || err?.message || 'Failed to fetch Shopify-New stocks'
    }
  }
}

export default defineEventHandler(async (event) => {
  try {
    return await handleFunc(event)
  } catch (err: any) {
    try {
      const authToken = await refreshTokenHelper(event)
      return await handleFunc(event, authToken)
    } catch (error: any) {
      const data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
      if([401, 402, 403, 407].includes(Number(data.status))) {
        //@ts-ignore
        setCookie(event, 'user', null)
      }
      return data
    }
  }
})
