import { string } from 'alga-js'
import refreshTokenHelper from "../../utils/refreshTokenHelper"
import forceLogoutHelper from "../../utils/forceLogoutHelper"
import errorHandlingHelper from "../../utils/errorHandlingHelper"
import getTokenHelper from "../../utils/getTokenHelper"
import fetchHelper from "../../utils/fetchHelper"
import { odataQuote } from "../../utils/odataHelper"

const handleFunc = async (event: any, authToken: any = null) => {
  let data: any = {}
  const token = authToken ?? await getTokenHelper(event)
  const body = await readBody(event)
  const searchTerm = body?.search || ''
  const organizationId = body?.organizationId || null

  if (!searchTerm) {
    throw createError({
      statusCode: 400,
      statusMessage: 'Search term is required'
    })
  }

  // Convert search term to lowercase for case-insensitive search,
  // quote-escaped for the OData string literals below
  const searchTermLower = odataQuote(searchTerm.toLowerCase())

  // Build organization filter if provided (coerced to number)
  const orgFilter = organizationId ? ` AND AD_Org_ID eq ${Number(organizationId)}` : ''

  const shipmentExpand = string.urlEncode('m_inoutline($expand=m_product_id,c_uom_id,m_locator_id),C_Order_ID,C_BPartner_ID,C_BPartner_Location_ID,AD_User_ID,M_Warehouse_ID,AD_Org_ID')
  const shipmentOrderby = string.urlEncode('MovementDate desc')

  // 1. First try: Search for Orders by ExternalOrderId
  const orderFilter = string.urlEncode(
    `contains(tolower(ExternalOrderId),'${searchTermLower}') AND isActive eq true AND DocStatus eq 'CO'${orgFilter}`
  )

  const orderRes: any = await fetchHelper(
    event,
    `models/c_order?$filter=${orderFilter}&$expand=C_BPartner_ID&$top=30`,
    'GET',
    token,
    null
  )

  const orderIds: number[] = []
  const bpartnersMap = new Map()

  if (orderRes?.records?.length > 0) {
    orderRes.records.forEach((order: any) => {
      orderIds.push(order.id)
      if (order.C_BPartner_ID?.id && !bpartnersMap.has(order.C_BPartner_ID.id)) {
        bpartnersMap.set(order.C_BPartner_ID.id, {
          id: order.C_BPartner_ID.id,
          name: order.C_BPartner_ID.Name || order.C_BPartner_ID.identifier,
          value: order.C_BPartner_ID.Value
        })
      }
    })

    // Fetch shipments for the matched orders
    const orderFilters = orderIds.map((id: number) => `C_Order_ID eq ${id}`).join(' OR ')
    const shipmentFilter = string.urlEncode(
      `MovementType eq 'C-' AND isActive eq true AND DocStatus eq 'CO' AND (${orderFilters})`
    )

    const shipmentsRes: any = await fetchHelper(
      event,
      `models/m_inout?$filter=${shipmentFilter}&$expand=${shipmentExpand}&$orderby=${shipmentOrderby}&$top=50`,
      'GET',
      token,
      null
    )

    data = {
      bpartners: Array.from(bpartnersMap.values()),
      shipments: shipmentsRes?.records || []
    }

    return data
  }

  // 2. Fallback: Search by BPartner name and location
  const bpartnerIdSet = new Set<number>()

  const bpartnerFilter = string.urlEncode(
    `(contains(tolower(Name),'${searchTermLower}') OR contains(tolower(Name2),'${searchTermLower}')) AND isActive eq true${orgFilter}`
  )

  const bpartnerRes: any = await fetchHelper(
    event,
    `models/c_bpartner?$filter=${bpartnerFilter}&$top=30`,
    'GET',
    token,
    null
  )

  if (bpartnerRes?.records) {
    bpartnerRes.records.forEach((bp: any) => bpartnerIdSet.add(bp.id))
  }

  const locationFilter = string.urlEncode(
    `(contains(tolower(Name),'${searchTermLower}') OR contains(tolower(Name2),'${searchTermLower}')) AND isActive eq true${orgFilter}`
  )

  const locationRes: any = await fetchHelper(
    event,
    `models/c_bpartner_location?$filter=${locationFilter}&$expand=C_BPartner_ID&$top=30`,
    'GET',
    token,
    null
  )

  if (locationRes?.records) {
    locationRes.records.forEach((loc: any) => {
      if (loc.C_BPartner_ID?.id) {
        bpartnerIdSet.add(loc.C_BPartner_ID.id)
      }
    })
  }

  if (bpartnerIdSet.size === 0) {
    return {
      bpartners: [],
      shipments: []
    }
  }

  const bpartnerIds = Array.from(bpartnerIdSet)
  const shipmentFilters = bpartnerIds.map((id: number) => `C_BPartner_ID eq ${id}`).join(' OR ')
  const shipmentFilter = string.urlEncode(
    `MovementType eq 'C-' AND isActive eq true AND DocStatus eq 'CO' AND (${shipmentFilters})`
  )

  const shipmentsRes: any = await fetchHelper(
    event,
    `models/m_inout?$filter=${shipmentFilter}&$expand=${shipmentExpand}&$orderby=${shipmentOrderby}&$top=50`,
    'GET',
    token,
    null
  )

  // Build bpartners list
  if (bpartnerRes?.records) {
    bpartnerRes.records.forEach((bp: any) => {
      bpartnersMap.set(bp.id, { id: bp.id, name: bp.Name, value: bp.Value })
    })
  }
  if (locationRes?.records) {
    locationRes.records.forEach((loc: any) => {
      if (loc.C_BPartner_ID?.id && !bpartnersMap.has(loc.C_BPartner_ID.id)) {
        bpartnersMap.set(loc.C_BPartner_ID.id, {
          id: loc.C_BPartner_ID.id,
          name: loc.C_BPartner_ID.Name || loc.C_BPartner_ID.identifier,
          value: loc.C_BPartner_ID.Value
        })
      }
    })
  }

  data = {
    bpartners: Array.from(bpartnersMap.values()),
    shipments: shipmentsRes?.records || []
  }

  return data
}

export default defineEventHandler(async (event) => {
  // Auth-only retry: a business 404 no longer triggers a token refresh.
  return await withAuthRetry(event, handleFunc)
})
