/**
 * POST /api/materials/products/quick-store  (multipart)
 *
 * Minimal product creation for the "quick product" modal on /materials/products:
 *   parts: name (required), price (number, optional → 0), priceListVersionIds (JSON array),
 *          priceListVersionPrices (JSON object versionId → price, overrides `price` per version),
 *          productCategoryId (optional, staff only — otherwise category "Standard"),
 *          organizationId (falls back to the org cookie), image (optional file)
 *
 * Defaults resolved from iDempiere (cached 10 min): product category "Standard",
 * UOM "Each", tax category "Standard" (each with an IsDefault fallback).
 * After the product POST nothing may throw any more (a refresh-retry would create
 * a duplicate product) — Strapi record, image upload, prices and the Laravel sync
 * are best-effort and reported in `warnings` / `prices`.
 */
import { string } from 'alga-js'
import refreshTokenHelper from '../../../utils/refreshTokenHelper'
import errorHandlingHelper from '../../../utils/errorHandlingHelper'
import fetchHelper from '../../../utils/fetchHelper'
import strapiHelper from '../../../utils/strapiHelper'
import laravelHelper from '../../../utils/laravelHelper'

const DEFAULTS_TTL_MS = 10 * 60 * 1000
let defaultsCache: { at: number; value: any } | null = null

const findFirst = async (event: any, token: string, model: string, filters: string[]) => {
  for (const filter of filters) {
    const res: any = await fetchHelper(event, `models/${model}?$filter=${string.urlEncode(filter)}&$top=1`, 'GET', token, null)
    if (res?.records?.[0]?.id) return res.records[0]
  }
  return null
}

const resolveDefaults = async (event: any, token: string) => {
  if (defaultsCache && Date.now() - defaultsCache.at < DEFAULTS_TTL_MS) return defaultsCache.value
  const [category, uom, taxCategory] = await Promise.all([
    findFirst(event, token, 'm_product_category', ["Name eq 'Standard' AND IsActive eq true", 'IsDefault eq true AND IsActive eq true']),
    findFirst(event, token, 'c_uom', ["Name eq 'Each' AND IsActive eq true", "X12DE355 eq 'EA' AND IsActive eq true", 'IsDefault eq true AND IsActive eq true']),
    findFirst(event, token, 'c_taxcategory', ["Name eq 'Standard' AND IsActive eq true", 'IsDefault eq true AND IsActive eq true'])
  ])
  const value = {
    categoryId: category?.id ?? null, category: category?.Name || '',
    uomId: uom?.id ?? null, uom: uom?.Name || '',
    taxCategoryId: taxCategory?.id ?? null, taxCategory: taxCategory?.Name || ''
  }
  if (value.categoryId && value.uomId && value.taxCategoryId) defaultsCache = { at: Date.now(), value }
  return value
}

const uploadProductImage = async (strapiNumericId: number, productId: number, productUu: string, file: { buffer: Buffer; filename: string; mime: string }) => {
  const config: any = useRuntimeConfig()
  const uploadBase = (config.api?.strapiupload
    || (config.public?.strapi || config.api?.strapi || '').replace(/\/media-api\/?$/, '')
  ).replace(/\/$/, '')
  // Native FormData + Blob (undici sets the multipart boundary) — same as inbox/strapiAttach.ts.
  const fd: any = new FormData()
  fd.append('field', 'image')
  fd.append('ref', 'api::m-product.m-product')
  fd.append('refId', String(strapiNumericId))
  fd.append('files', new Blob([file.buffer], { type: file.mime || 'image/jpeg' }), file.filename)
  fd.append('fileInfo', JSON.stringify({ caption: String(productId), alternativeText: String(productUu || '') }))
  const up: any = await $fetch(`${uploadBase}/api/upload`, {
    method: 'POST',
    headers: { Authorization: `Bearer ${config.api?.strapitoken}` },
    body: fd
  })
  const uploaded = Array.isArray(up) ? up[0] : (up?.[0] ?? up)
  return uploaded?.id ?? null
}

export default defineEventHandler(async (event) => {
  // Multipart body can only be read once — parse before any token work.
  const form = await readMultipartFormData(event)
  if (!form) return { status: 400, message: 'Empty request' }

  const fields: Record<string, string> = {}
  let image: { buffer: Buffer; filename: string; mime: string } | null = null
  for (const part of form) {
    if (!part.name) continue
    if (part.filename && part.data?.length) {
      if (part.name === 'image') image = { buffer: part.data, filename: part.filename, mime: (part as any).type || 'image/jpeg' }
    } else {
      fields[part.name] = part.data?.toString('utf8') ?? ''
    }
  }

  const name = String(fields.name || '').trim()
  if (!name) return { status: 400, message: 'Name is required' }
  if (image && !/^image\//i.test(image.mime)) return { status: 415, message: 'Only image files are allowed' }

  const organizationId = fields.organizationId || getCookie(event, 'logship_organization_id')
  if (!organizationId) return { status: 400, message: 'No organization context' }

  const price = Number(String(fields.price || '0').replace(',', '.'))
  if (!Number.isFinite(price) || price < 0) return { status: 400, message: 'Invalid price' }

  let versionIds: number[] = []
  try { versionIds = (JSON.parse(fields.priceListVersionIds || '[]') || []).map(Number).filter((n: number) => Number.isFinite(n) && n > 0) } catch {}

  const overrides: Record<string, number> = {}
  try {
    const raw = JSON.parse(fields.priceListVersionPrices || '{}') || {}
    for (const [k, v] of Object.entries(raw)) {
      const n = Number(String(v ?? '').replace(',', '.'))
      if (Number.isFinite(n) && n >= 0) overrides[String(Number(k))] = n
    }
  } catch {}
  const priceFor = (versionId: number) => overrides[String(versionId)] ?? price

  const customCategoryId = Number(fields.productCategoryId || 0) > 0 ? Number(fields.productCategoryId) : null

  const userId = getCookie(event, 'logship_user_id')

  const persist = async (token: string) => {
    const defaults = await resolveDefaults(event, token)
    const missing = [!defaults.categoryId && 'product category "Standard"', !defaults.uomId && 'UOM "Each"', !defaults.taxCategoryId && 'tax category "Standard"'].filter(Boolean)
    if (missing.length) return { status: 422, message: 'Default not found: ' + missing.join(', ') }

    // Optional category override (staff): must be an active category, otherwise fall back to "Standard".
    let categoryId = defaults.categoryId
    let categoryName = defaults.category
    if (customCategoryId) {
      const cat: any = await fetchHelper(event, 'models/m_product_category/' + customCategoryId, 'GET', token, null)
      if (cat?.id && (cat?.IsActive ?? cat?.isActive ?? true) !== false) { categoryId = cat.id; categoryName = cat.Name || '' }
    }

    // ---- 1. product (the only write that may throw → refresh-retry safe) ----
    const product: any = await fetchHelper(event, 'models/m_product', 'POST', token, {
      AD_Org_ID: { id: Number(organizationId), tableName: 'AD_Org' },
      isActive: true,
      name,
      value: '',
      isSummary: false,
      isStocked: true,
      isPurchased: true,
      isSold: true,
      discontinued: false,
      isBOM: false,
      ProductType: { id: 'I' },
      M_Product_Category_ID: { id: categoryId, tableName: 'M_Product_Category' },
      C_UOM_ID: { id: defaults.uomId, tableName: 'C_UOM' },
      C_TaxCategory_ID: { id: defaults.taxCategoryId, tableName: 'C_TaxCategory' },
      labelprinter: { id: 'b' },
      ...(userId ? { SalesRep_ID: { id: Number(userId), tableName: 'AD_User' } } : {}),
      tableName: 'M_Product'
    })
    if (!product?.id) return { status: 500, message: 'Product was not created' }

    const warnings: string[] = []
    const result: any = {
      status: 200, message: '',
      id: product.id, uid: product.uid, value: product.Value, name: product.Name,
      defaults,
      category: categoryName,
      categoryId,
      organizationId: Number(organizationId),
      organization: product?.AD_Org_ID?.identifier || '',
      strapi: { id: null, documentId: null },
      imageUploaded: false,
      prices: [] as any[],
      warnings
    }

    // ---- 2. Strapi record + link (best-effort) ----
    try {
      const sp: any = await strapiHelper(event, 'm-products', 'POST', {
        data: { M_Product_ID: product.id, value: product.Value, name: product.Name }
      })
      if (sp?.data?.id) {
        result.strapi = { id: sp.data.id, documentId: sp.data.documentId }
        try {
          await fetchHelper(event, 'models/m_product/' + product.id, 'PUT', token, {
            Strapi_Product_ID: sp.data.id,
            Strapi_Product_documentId: sp.data.documentId
          })
        } catch (e: any) { warnings.push('Strapi link not stored on the product: ' + (e?.data?.detail || e?.message || e)) }
      } else {
        warnings.push('Strapi product record not created')
      }
    } catch (e: any) {
      warnings.push('Strapi product record not created: ' + (e?.data?.error?.message || e?.message || e))
    }

    // ---- 3. image (best-effort) ----
    if (image && result.strapi.id) {
      try {
        const fileId = await uploadProductImage(result.strapi.id, product.id, product.uid, image)
        result.imageUploaded = !!fileId
        if (fileId && result.strapi.documentId) {
          try { await strapiHelper(event, `m-products/${result.strapi.documentId}`, 'PUT', { data: { Main_Image: fileId } }) } catch {}
        }
      } catch (e: any) {
        warnings.push('Image upload failed: ' + (e?.data?.error?.message || e?.message || e))
      }
    } else if (image) {
      warnings.push('Image skipped (no Strapi product record)')
    }

    // ---- 4. prices (best-effort, one per version) ----
    for (const versionId of versionIds) {
      const versionPrice = priceFor(versionId)
      try {
        const pp: any = await fetchHelper(event, 'models/m_productprice', 'POST', token, {
          AD_Org_ID: { id: Number(organizationId), tableName: 'AD_Org' },
          isActive: true,
          priceList: versionPrice,
          priceStd: versionPrice,
          priceLimit: versionPrice,
          M_Product_ID: { id: product.id, tableName: 'M_Product' },
          M_PriceList_Version_ID: { id: versionId, tableName: 'M_PriceList_Version' },
          tableName: 'M_ProductPrice'
        })
        result.prices.push({ versionId, id: pp?.id ?? null, ok: !!pp?.id, price: versionPrice })
      } catch (e: any) {
        const msg = e?.data?.detail || e?.data?.title || e?.message || String(e)
        result.prices.push({ versionId, ok: false, message: msg })
        warnings.push(`Price for version ${versionId} failed: ${msg}`)
      }
    }

    // ---- 5. Laravel sync (best-effort, same as the full create) ----
    try { await laravelHelper(event, '/inventories/products/sync-idempiere', 'POST', null) } catch {}

    return result
  }

  let firstError: any = null
  try {
    return await persist(await getTokenHelper(event))
  } catch (err: any) {
    firstError = err
  }
  try {
    return await persist(await refreshTokenHelper(event))
  } catch (error: any) {
    return errorHandlingHelper(firstError?.data ?? firstError, error?.data ?? error)
  }
})
