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

// GET /api/shopify-new/locations?orderSourceId=123
// Returns all Shopify locations for the shop plus a default location to preselect.
// Default priority: Shopify_Location_ID on the order source > first active location
// that ships inventory / fulfills online orders > first active location.
// If the locations query is denied (missing read_locations scope), falls back to
// deriving locations from inventory levels of a sample of variants.
const handleFunc = async (event: any, authToken: any = null) => {
  const token = authToken ?? await getTokenHelper(event)
  const query = getQuery(event)
  const orderSourceId = query.orderSourceId as string

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

  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 locations: Record<string, { id: string, name: string, active: boolean, shipsInventory: boolean, fulfillsOnlineOrders: boolean }> = {}
    let locationsQueryError = ''

    // Preferred: the locations query (requires the read_locations scope)
    try {
      const locationsQuery = `{
        locations(first: 50) {
          edges {
            node {
              id
              name
              isActive
              shipsInventory
              fulfillsOnlineOrders
            }
          }
        }
      }`
      const locRes = await shopifyNewGraphQL(graphqlUrl, accessToken, locationsQuery)
      for(const edge of (locRes?.data?.locations?.edges || [])) {
        const node = edge.node
        const numericId = parseShopifyGid(node.id)
        locations[numericId] = {
          id: numericId,
          name: node.name || `Location ${numericId}`,
          active: node.isActive ?? true,
          shipsInventory: node.shipsInventory ?? true,
          fulfillsOnlineOrders: node.fulfillsOnlineOrders ?? false
        }
      }
    } catch (locErr: any) {
      locationsQueryError = locErr?.message || String(locErr)
      console.log('shopify-new: locations query failed, trying inventory-level fallback:', locationsQueryError)
    }

    // Fallback: derive locations from the inventory levels of a sample of variants.
    // Needs only read_products + read_inventory, which the stock page requires anyway.
    if(Object.keys(locations).length === 0) {
      try {
        const scanQuery = `{
          productVariants(first: 30) {
            edges {
              node {
                inventoryItem {
                  inventoryLevels(first: 10) {
                    edges { node { location { id name isActive } } }
                  }
                }
              }
            }
          }
        }`
        const scanRes = await shopifyNewGraphQL(graphqlUrl, accessToken, scanQuery)
        for(const vEdge of (scanRes?.data?.productVariants?.edges || [])) {
          for(const lEdge of (vEdge?.node?.inventoryItem?.inventoryLevels?.edges || [])) {
            const loc = lEdge?.node?.location
            if(!loc?.id) continue
            const numericId = parseShopifyGid(loc.id)
            if(!locations[numericId]) {
              locations[numericId] = {
                id: numericId,
                name: loc.name || `Location ${numericId}`,
                active: loc.isActive ?? true,
                shipsInventory: true,
                fulfillsOnlineOrders: false
              }
            }
          }
        }
        if(Object.keys(locations).length > 0) {
          console.log(`shopify-new: Derived ${Object.keys(locations).length} location(s) from inventory levels`)
        }
      } catch (scanErr: any) {
        console.log('shopify-new: inventory-level location fallback failed:', scanErr?.message)
        if(!locationsQueryError) locationsQueryError = scanErr?.message || String(scanErr)
      }
    }

    if(Object.keys(locations).length === 0) {
      return {
        status: 400,
        message: `No Shopify locations accessible${locationsQueryError ? ` — ${locationsQueryError}` : ''}. Grant the app the read_locations scope, or set Shopify_Location_ID on the order source.`,
        locations: {},
        defaultLocationId: ''
      }
    }

    // iDempiere returns the ColumnName casing verbatim — the column is shopify_location_id
    const osLocationRaw = os?.shopify_location_id ?? os?.Shopify_Location_ID
    const osLocationId = osLocationRaw ? String(osLocationRaw) : ''
    // A configured default always appears in the list, even if the (possibly
    // fallback-derived) location scan didn't surface it
    if(osLocationId && !locations[osLocationId]) {
      locations[osLocationId] = {
        id: osLocationId,
        name: `Location ${osLocationId}`,
        active: true,
        shipsInventory: true,
        fulfillsOnlineOrders: false
      }
    }
    const active = Object.values(locations).filter((l) => l.active)
    const defaultFromOrderSource = !!(osLocationId && locations[osLocationId])
    let defaultLocationId = defaultFromOrderSource ? osLocationId : ''
    if(!defaultLocationId) {
      const preferred = active.find((l) => l.fulfillsOnlineOrders && l.shipsInventory)
        || active.find((l) => l.shipsInventory)
        || active[0]
      defaultLocationId = preferred?.id || ''
    }

    return {
      status: 200,
      locations,
      defaultLocationId,
      defaultFromOrderSource
    }
  } catch (err: any) {
    console.error('shopify-new locations error:', err?.message || err)
    return {
      status: Number(err?.status || err?.response?.status || 500),
      message: err?.message || 'Failed to fetch Shopify locations',
      locations: {},
      defaultLocationId: ''
    }
  }
}

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
    }
  }
})
