import fetchHelper from './fetchHelper'

/**
 * Creates a tracking ticket (r_request) for a production (m_production).
 *
 * The ticket links the production (M_Production_ID), the sales order when one
 * exists (C_Order_ID), the produced product (M_Product_ID) and always the
 * merchant org (AD_Org_ID). C_BPartner_ID is set to the business partner
 * linked to that organization (ad_org.C_BPartner_ID) — NOT the order's
 * customer — so time booked on the ticket is billed to the merchant.
 *
 * Callers must treat a throw as non-fatal: the production itself is already
 * created and must never be rolled back because the ticket failed.
 *
 * `cache` (optional) avoids refetching the org bpartner / request type when
 * creating many tickets in one call (BOM production batch).
 */
export interface ProductionTicketOpts {
  organizationId: number | string
  productionId: number | string
  productionDocumentNo?: string
  productId?: number | string
  productName?: string
  qty?: number | string
  orderId?: number | string
  orderDocumentNo?: string
}

/**
 * Resolves the sales order a production was created for, via
 * m_production.C_OrderLine_ID → c_orderline.C_Order_ID. Returns nulls when the
 * production has no order line (manual productions). Two bounded $select GETs.
 */
export const resolveProductionOrder = async (event: any, token: string | null, productionId: number | string) => {
  const empty = { orderId: null as number | null, orderLineId: null as number | null, orderDocumentNo: '' }
  if (!productionId) return empty
  const prod: any = await fetchHelper(event, `models/m_production/${productionId}?$select=C_OrderLine_ID,DocumentNo`, 'GET', token, null)
  const orderLineId = prod?.C_OrderLine_ID?.id ?? null
  if (!orderLineId) return empty
  const line: any = await fetchHelper(event, `models/c_orderline/${orderLineId}?$select=C_Order_ID`, 'GET', token, null)
  const orderId = line?.C_Order_ID?.id ?? null
  return {
    orderId,
    orderLineId,
    orderDocumentNo: String(line?.C_Order_ID?.identifier || '').split('_')[0]
  }
}

/**
 * Ticket write rule: relating a production to a ticket also relates the order
 * that production was made for — unless the caller already sends an order.
 * Mutates `newObjValue` (C_Order_ID) and returns the resolved order id, or null
 * when nothing was changed. `currentOrderId` / `currentProductionId` are the
 * ticket's persisted values (update path) so an unchanged production link on a
 * ticket that already has an order is left alone.
 */
export const linkOrderFromProduction = async (
  event: any,
  token: string | null,
  body: any,
  newObjValue: any,
  current: { orderId?: number | null, productionId?: number | null } = {}
): Promise<number | null> => {
  const productionId = body?.productionId
  if (!productionId || body?.orderId) return null
  const linkIsNew = current.productionId == null || Number(current.productionId) !== Number(productionId)
  const hasOrder = !!current.orderId
  if (!linkIsNew && hasOrder) return null
  try {
    const { orderId } = await resolveProductionOrder(event, token, productionId)
    if (!orderId) return null
    newObjValue.C_Order_ID = { id: orderId, tableName: 'C_Order' }
    return orderId
  } catch (err: any) {
    console.warn('[productionTicket] could not derive order from production', productionId, err?.message || err)
    return null
  }
}

export const createProductionTicket = async (event: any, token: string, opts: ProductionTicketOpts, cache: any = {}) => {
  // Business partner linked to the merchant org (same resolution as
  // /api/admin/organizations/[id]/bpartner — one bounded $select fetch).
  if (!cache.orgBPartner) cache.orgBPartner = {}
  let orgBPartnerId = cache.orgBPartner[opts.organizationId]
  if (orgBPartnerId === undefined) {
    const orgRes: any = await fetchHelper(event, `models/ad_org/${opts.organizationId}?$select=C_BPartner_ID`, 'GET', token, null)
    orgBPartnerId = orgRes?.C_BPartner_ID?.id ?? null
    cache.orgBPartner[opts.organizationId] = orgBPartnerId
  }

  // First active request type — same fallback the request create page uses.
  if (cache.requestTypeId === undefined) {
    const rtRes: any = await fetchHelper(event, `models/r_requesttype?$filter=${encodeURIComponent('IsActive eq true')}&$top=1`, 'GET', token, null)
    cache.requestTypeId = rtRes?.records?.[0]?.id ?? null
  }
  if (!cache.requestTypeId) throw new Error('No active request type (r_requesttype) found')

  const productName = String(opts.productName || '').replace(/^-1_/, '')
  const qty = Number(opts.qty || 0)
  const summaryParts = [
    `Produktion ${opts.productionDocumentNo || opts.productionId}`
      + (productName ? `: ${productName}` : '')
      + (qty > 0 ? ` (${qty} Stk)` : '')
      + (opts.orderDocumentNo ? ` — Auftrag ${opts.orderDocumentNo}` : ''),
    'Ticket zur Erfassung von Zeiten und Arbeitsschritten dieser Produktion.'
  ]

  let refValues: any = {}
  if (orgBPartnerId) {
    refValues = {...refValues,
      C_BPartner_ID: {
        id: orgBPartnerId,
        tableName: 'C_BPartner'
      }
    }
  }
  if (opts.orderId) {
    refValues = {...refValues,
      C_Order_ID: {
        id: opts.orderId,
        tableName: 'C_Order'
      }
    }
  }
  if (opts.productId) {
    refValues = {...refValues,
      M_Product_ID: {
        id: opts.productId,
        tableName: 'M_Product'
      }
    }
  }
  const salesRepId = getCookie(event, 'logship_user_id')
  if (salesRepId) {
    refValues = {...refValues,
      SalesRep_ID: {
        id: Number(salesRepId),
        tableName: 'AD_User'
      }
    }
  }

  const res: any = await fetchHelper(event, 'models/r_request', 'POST', token, {
    AD_Org_ID: {
      id: opts.organizationId,
      tableName: 'AD_Org'
    },
    R_RequestType_ID: {
      id: cache.requestTypeId,
      tableName: 'R_RequestType'
    },
    M_Production_ID: {
      id: opts.productionId,
      tableName: 'M_Production'
    },
    Priority: { id: '5' },
    DueType: { id: '5' },
    ConfidentialType: { id: 'I' },
    ConfidentialTypeEntry: { id: 'I' },
    summary: summaryParts.join('\n'),
    dateLastAction: new Date().toJSON().replace(/\.\d{3}Z$/, 'Z'),
    isActive: true,
    isEscalated: false,
    processed: false,
    isSelfService: false,
    isInvoiced: false,
    requestAmt: 0,
    qtySpent: 0,
    qtyInvoiced: 0,
    ...refValues,
    tableName: 'R_Request'
  })
  if (!res?.id) throw new Error('Ticket (r_request) could not be created')
  return res
}
