import { defineSisHandler } from "../../../../utils/listings/routeHelper"
import { listListings } from "../../../../utils/listings/listingStore"
import { enrichWithProducts } from "../../../../utils/sisMatching"
import { amazonDomainForOrderSource } from "../../../../utils/amazonSpApi"
import { marketplaceKeyOf, marketplaceLabel, supportsListings } from "../../../../utils/listings/adapters"
import { shopifyStoreHandle } from "../../../../utils/listings/adapters/shopify"
import { shopwareUrls } from "../../../../utils/listings/adapters/shopware"
import { string } from 'alga-js'

// GET /api/sales/sis/listings?orderSourceId=1,2,3&includeInactive=1   — one or several order sources
// GET /api/sales/sis/listings?all=1                                    — every order source with a listings adapter
// The persisted listings (CUST_MarketplaceListing) joined with the internal product data
// (price list price, qty on hand, BOM components). iDempiere only — no marketplace call.
// `sources` carries the per-source marketplace / link data the page needs for mixed lists.
const sourceInfo = (os: any) => {
  const marketplace = marketplaceKeyOf(os)
  const shopDomain = String(os?.marketplace_url || os?.Marketplace_URL || '').replace(/^https?:\/\//i, '').replace(/\/.*$/, '')
  return {
    id: Number(os.id), name: os.Name || '', orgId: Number(os?.AD_Org_ID?.id) || 0, orgName: os?.AD_Org_ID?.identifier || '',
    marketplace, marketplaceName: marketplaceLabel(marketplace), supportsListings: supportsListings(os),
    marketplaceDomain: amazonDomainForOrderSource(os),
    shop: marketplace.startsWith('shopify') ? { storeHandle: shopifyStoreHandle(os), domain: shopDomain }
      : marketplace === 'shopware' ? { baseUrl: shopwareUrls(os).baseUrl } : null
  }
}

export default defineSisHandler(async ({ event, token, f }) => {
  const q = getQuery(event)
  const all = q.all === '1' || q.all === 'true'
  const ids = String(q.orderSourceId || '').split(',').map(s => Number(s.trim())).filter(n => Number.isFinite(n) && n > 0)
  if (!all && !ids.length) return { status: 400, message: 'orderSourceId (comma separated) or all=1 is required' }

  let sources: any[] = []
  if (all) {
    const res: any = await f(`models/c_ordersource?$filter=${string.urlEncode('isActive eq true')}&$orderby=${string.urlEncode('Name asc')}&$top=500`)
    sources = (res?.records || []).filter((os: any) => supportsListings(os))
  } else {
    for (const id of ids) {
      const os: any = await f(`models/c_ordersource/${id}`)
      if (os?.id) sources.push(os)
    }
    if (!sources.length) return { status: 404, message: 'Order source not found' }
  }

  const infos = Object.fromEntries(sources.map(os => [String(os.id), sourceInfo(os)]))
  const activeOnly = q.includeInactive !== '1'
  const listings: any[] = []
  for (const os of sources) listings.push(...await listListings(f, Number(os.id), { activeOnly, top: 5000 }))

  // product enrichment is org-scoped (return locators) → one call per org
  const config: any = useRuntimeConfig(event)
  const priceListId = config.public?.pricelistid || '101'
  const enrich = new Map<number, any>()
  const byOrg = new Map<number, number[]>()
  for (const l of listings) {
    if (!l.productId) continue
    const orgId = infos[String(l.orderSourceId)]?.orgId || 0
    byOrg.set(orgId, [...(byOrg.get(orgId) || []), l.productId])
  }
  for (const [orgId, productIds] of byOrg) for (const [pid, e] of await enrichWithProducts(event, token, orgId, productIds, priceListId)) enrich.set(pid, e)

  const rows = listings.map(l => {
    const p = l.productId ? enrich.get(l.productId) : null
    const src = infos[String(l.orderSourceId)]
    return {
      ...l,
      orderSourceName: src?.name || l.orderSourceName || '',
      marketplace: src?.marketplace || 'unknown',
      productName: p?.productName || '',
      productValue: p?.productValue || '',
      productAsin: p?.asin || null,
      strapiProductDocumentId: p?.strapiProductDocumentId || null,
      isBom: p?.isBom || false,
      // BOM: components carry the stock, not the bundle → the FIRST component's qty is the row's
      // internal qty (all components with qty per bundle + stock go to the tooltip).
      bomComponents: p?.bomComponents || [],
      bomOwnQtyOnHand: p?.isBom ? (p?.internalQtyOnHand ?? null) : null,
      internalPrice: p?.internalPrice ?? null,
      internalQtyOnHand: p?.bomComponents?.[0] ? p.bomComponents[0].onHand : (p?.internalQtyOnHand ?? null),
      returnQtyOnHand: p?.bomComponents?.[0] ? p.bomComponents[0].returnOnHand : (p?.returnQtyOnHand ?? 0)
    }
  })
  const counts = {
    total: rows.length,
    matched: rows.filter(r => r.productId).length,
    unmatched: rows.filter(r => !r.productId).length,
    queued: rows.filter(r => r.syncStatus === 'queued' || r.syncStatus === 'sending').length,
    sent: rows.filter(r => r.syncStatus === 'sent').length,
    errors: rows.filter(r => r.syncStatus === 'error').length,
    delisted: rows.filter(r => r.listingStatus === 'delisted').length
  }
  const first = infos[String(sources[0]?.id)]
  return {
    status: 200, all, sources: infos,
    // single-source fields kept for callers that pass one id
    orderSourceId: first?.id ?? null, orgId: first?.orgId ?? null, orderSourceName: first?.name || '',
    marketplace: first?.marketplace, marketplaceName: first?.marketplaceName, supportsListings: first?.supportsListings,
    marketplaceDomain: first?.marketplaceDomain, shop: first?.shop ?? null,
    rows, counts
  }
})
