/**
 * Bulk creation of M_Locator rows for one warehouse (Auto-Generate, Warehouse Builder
 * "create missing", import wizard). Dedupes by X|Y|Z against the warehouse's existing rows,
 * POSTs with small concurrency, never throws per row (collects `failed`).
 * Write shape = the proven lowercase one from locatorCatalog.ensureLocator.
 */
import fetchHelper from './fetchHelper'
import pLimit from './pLimit'
import { bustLocatorCache, loadWarehouseLocators } from './warehouseLayout'
import { xyzKey } from '../../app/utils/warehouseLayout/wiring'

export interface BulkLocatorItem { x: string; y: string; z: string; value?: string; priorityNo?: number; locatorTypeId?: number | null }
export interface BulkCreateOptions {
  warehouseId: number
  organizationId: number
  items: BulkLocatorItem[]
  priorityNo?: number
  isActive?: boolean
  locatorTypeId?: number | null
  concurrency?: number
}
export interface BulkCreateResult {
  created: Array<{ id: number; value: string; x: string; y: string; z: string }>
  skipped: Array<{ value: string; reason: string }>
  failed: Array<{ value: string; message: string }>
  totalRequested: number
}

export const MAX_BULK_ITEMS = 500

export async function bulkCreateLocators (event: any, token: string, opts: BulkCreateOptions): Promise<BulkCreateResult> {
  const result: BulkCreateResult = { created: [], skipped: [], failed: [], totalRequested: opts.items.length }
  const existing = await loadWarehouseLocators(event, token, opts.warehouseId, true)
  const have = new Set(existing.records.map(r => xyzKey(r.x, r.y, r.z)))
  const haveValue = new Set(existing.records.map(r => String(r.value).trim().toLowerCase()))
  const seen = new Set<string>()
  const todo: BulkLocatorItem[] = []
  for (const raw of opts.items.slice(0, MAX_BULK_ITEMS)) {
    const x = String(raw.x ?? '').trim(), y = String(raw.y ?? '').trim(), z = String(raw.z ?? '').trim()
    const value = String(raw.value || `${x}-${y}-${z}`).trim()
    if (!x || !y || !z) { result.skipped.push({ value, reason: 'incomplete' }); continue }
    const k = xyzKey(x, y, z)
    if (seen.has(k)) { result.skipped.push({ value, reason: 'duplicate in request' }); continue }
    seen.add(k)
    if (have.has(k) || haveValue.has(value.toLowerCase())) { result.skipped.push({ value, reason: 'exists' }); continue }
    todo.push({ x, y, z, value, priorityNo: raw.priorityNo, locatorTypeId: raw.locatorTypeId })
  }
  const limit = pLimit(opts.concurrency ?? 4)
  await Promise.all(todo.map(it => limit(async () => {
    const payload: any = {
      AD_Org_ID: { id: Number(opts.organizationId), tableName: 'AD_Org' },
      M_Warehouse_ID: { id: Number(opts.warehouseId), tableName: 'M_Warehouse' },
      value: it.value,
      x: it.x, y: it.y, z: it.z,
      priorityNo: Number(it.priorityNo ?? opts.priorityNo ?? 50) || 50,
      isActive: opts.isActive !== false,
      isDefault: false
    }
    const lt = it.locatorTypeId ?? opts.locatorTypeId
    if (lt) payload.M_LocatorType_ID = { id: Number(lt), tableName: 'M_LocatorType' }
    try {
      const res: any = await fetchHelper(event, 'models/m_locator', 'POST', token, payload)
      if (res?.id) result.created.push({ id: Number(res.id), value: it.value!, x: it.x, y: it.y, z: it.z })
      else result.failed.push({ value: it.value!, message: 'no id returned' })
    } catch (err: any) {
      result.failed.push({ value: it.value!, message: String(err?.data?.detail ?? err?.data?.message ?? err?.message ?? err).slice(0, 300) })
    }
  })))
  bustLocatorCache(opts.warehouseId)
  return result
}
