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

const idempiereFilterName = (key: string) => {
  const map: Record<string, string> = {
    documentNo: 'DocumentNo',
    externalorderId: 'ExternalOrderId',
    partnerLocationName: 'ship_name',
    partnerLocationName2: 'ship_name2',
    locationZipCode: 'ship_postal',
    locationStreet: 'ship_address1',
    locationCity: 'ship_city',
    shipperName: 'shipper_name',
    grandTotal: 'GrandTotal',
    totalQty: 'TotalQty',
    fulfillmentFeeTotal: 'fulfillment_fee_total',
    trackingNo: 'TrackingNo',
    created: 'Created',
    // real view key column — bare 'id' is not queryable/orderable in iDempiere
    id: 'c_order_id',
  }
  return map[key] || ''
}

const sortFieldName = (key: string) => {
  const map: Record<string, string> = {
    documentNo: 'DocumentNo',
    organization: 'AD_Org_ID',
    externalorderId: 'ExternalOrderId',
    partnerLocationName: 'ship_name',
    partnerLocationName2: 'ship_name2',
    locationZipCode: 'ship_postal',
    locationStreet: 'ship_address1',
    locationCity: 'ship_city',
    shipperName: 'shipper_name',
    grandTotal: 'GrandTotal',
    fulfillmentFeeTotal: 'fulfillment_fee_total',
    trackingNo: 'TrackingNo',
    created: 'Created',
    id: 'c_order_id',
    totalQty: 'TotalQty',
    shippingDate: 'shipping_date',
    shipmentStatus: 'DocStatus',
  }
  return map[key] || ''
}

const filterHandler = (filterModel: any) => {
  if (!filterModel || Object.keys(filterModel).length === 0) return ''

  let parts: string[] = []
  for (const key of Object.keys(filterModel)) {
    const mapped = idempiereFilterName(key)
    if (!mapped) continue

    const item = filterModel[key]
    if (item.filterType === 'text') {
      const text = textFilterHandler(mapped, item)
      if (text) parts.push(text)
    } else if (item.filterType === 'number') {
      const num = numberFilterHandler(mapped, item)
      if (num) parts.push(num)
    } else if (item.filterType === 'date') {
      parts.push(`${mapped} eq ${item.dateFrom}`)
    }
  }

  if (parts.length === 0) return ''
  return ' AND (' + parts.join(' AND ') + ')'
}

const numberFilterHandler = (key: string, item: any) => {
  if (item.type === 'equals') return `${key} eq ${item.filter}`
  if (item.type === 'notEqual') return `${key} neq ${item.filter}`
  if (item.type === 'greaterThan') return `${key} gt ${item.filter}`
  if (item.type === 'greaterThanOrEqual') return `${key} ge ${item.filter}`
  if (item.type === 'lessThan') return `${key} lt ${item.filter}`
  if (item.type === 'lessThanOrEqual') return `${key} le ${item.filter}`
  if (item.type === 'inRange') return `${key} ge ${item.filter} AND ${key} le ${item.filterTo}`
  return ''
}

const textFilterHandler = (key: string, item: any) => {
  const val = item.filter?.toString() || ''
  const isFkField = key.endsWith('_ID')

  if (isFkField) {
    // FK fields: contains() matches against identifier text, upper() not supported
    const cleanVal = val.replaceAll('%', '')
    if (item.type === 'equals') return `${key} eq '${cleanVal}'`
    if (item.type === 'notEqual') return `${key} neq '${cleanVal}'`
    if (item.type === 'contains') return `contains(${key},'${cleanVal}')`
    if (item.type === 'notContains') return `not contains(${key},'${cleanVal}')`
    if (item.type === 'startsWith') return `startswith(${key},'${cleanVal}')`
    if (item.type === 'endsWith') return `endswith(${key},'${cleanVal}')`
    return ''
  }

  // Case-insensitive via tolower() (OData standard)
  const lowerKey = `tolower(${key})`
  const lowerVal = val.toLowerCase().replaceAll('%', '')
  if (item.type === 'equals') return `${lowerKey} eq '${lowerVal}'`
  if (item.type === 'notEqual') return `${lowerKey} neq '${lowerVal}'`
  if (item.type === 'contains') return `contains(${lowerKey},'${lowerVal}')`
  if (item.type === 'notContains') return `not contains(${lowerKey},'${lowerVal}')`
  if (item.type === 'startsWith') return `startswith(${lowerKey},'${lowerVal}')`
  if (item.type === 'endsWith') return `endswith(${lowerKey},'${lowerVal}')`
  return ''
}

const buildSortClause = (sortModel: any[]) => {
  if (!sortModel || sortModel.length === 0) return 'Created desc'

  const parts = sortModel
    .map(s => {
      const col = sortFieldName(s.colId)
      if (!col) return ''
      return `${col} ${s.sort}`
    })
    .filter(Boolean)

  return parts.length > 0 ? parts.join(',') : 'Created desc'
}


const calculateAge = (fromDate: string, toDate: string) => {
  if (!fromDate || !toDate) return ''
  const diffSeconds = Math.abs((new Date(toDate).getTime() - new Date(fromDate).getTime()) / 1000)
  if (diffSeconds < 3600) return Math.round(diffSeconds / 60) + ' minutes'
  if (diffSeconds < 86400) return Math.round(diffSeconds / 3600) + ' hours'
  return Math.round(diffSeconds / 86400) + ' days'
}

const mapRow = (item: any, serviceDocStatus?: any) => {
  // Build minout array from shipments_summary
  const minout: any[] = []
  if (item.shipments_summary) {
    item.shipments_summary.split(' | ').forEach((s: string) => {
      const [inoutId, docNo] = s.split(':')
      if (inoutId) {
        minout.push({
          id: parseInt(inoutId),
          DocumentNo: docNo,
          TrackingNo: item.TrackingNo || '',
          IsCommissioned: item.IsCommissioned,
          IsCommissionedConfirmed: item.IsCommissionedConfirmed,
          DocStatus: item.shipment_docstatus?.id || '',
          shipping_date: item.shipping_date,
        })
      }
    })
  }

  // Use service token DocStatus as fallback if user's token didn't return it
  const docStatus = item.DocStatus || serviceDocStatus || null
  const docStatusId = docStatus?.id || ''

  // Compute shipment status server-side
  let shipmentStatus = ''
  const shipmentDocStatusId = item.shipment_docstatus?.id || ''
  if (docStatusId === 'VO') {
    shipmentStatus = 'voided'
  } else if (docStatusId === 'DR') {
    shipmentStatus = 'drafted'
  } else if (docStatusId === 'IP') {
    shipmentStatus = 'in_progress'
  } else if (docStatusId === 'CO') {
    if (shipmentDocStatusId === 'CO' && item.TrackingNo) {
      shipmentStatus = 'shipped'
    } else if (shipmentDocStatusId === 'CO' && !item.TrackingNo) {
      shipmentStatus = 'packing'
    } else {
      shipmentStatus = 'incoming'
    }
  }

  // Build orderSource object
  const orderSource = {
    ...(item.C_OrderSource_ID || {}),
    Name: item.order_source_name || item.C_OrderSource_ID?.identifier || '',
    Description: item.order_source_description || '',
    Marketplace: { identifier: item.marketplace_name || '' },
  }

  return {
    marketplaceKey: item.marketplace_name || '',
    id: item.id,
    isActive: item.IsActive,
    documentNo: item.DocumentNo,
    description: item.Description || '',
    dateOrdered: item.DateOrdered,
    created: item.Created,
    grandTotal: item.GrandTotal,
    trackingNo: item.TrackingNo || '',
    isSOTrx: item.IsSOTrx,
    shipmentStatus: shipmentStatus,
    docStatus: docStatus?.identifier || '',
    docStatusId: docStatusId,
    docType: item.C_DocType_ID?.identifier || '',
    docTypeId: item.C_DocType_ID?.id || '',
    docTypeTarget: item.C_DocTypeTarget_ID?.identifier || '',
    docTypeTargetId: item.C_DocTypeTarget_ID?.id || '',
    currency: item.C_Currency_ID?.identifier || '',
    currencyId: item.C_Currency_ID?.id || '',
    priorityRule: item.PriorityRule?.identifier || '',
    priorityRuleId: item.PriorityRule?.id || '',
    warehouse: item.M_Warehouse_ID?.identifier || '',
    warehouseId: item.M_Warehouse_ID?.id || '',
    partner: item.C_BPartner_ID?.identifier || '',
    partnerId: item.C_BPartner_ID?.id || '',
    partnerLocation: item.C_BPartner_Location_ID || {},
    partnerLocationId: item.C_BPartner_Location_ID?.id || '',
    partnerLocationName: item.ship_name || '',
    partnerLocationName2: item.ship_name2 || '',
    billPartner: item.Bill_BPartner_ID?.identifier || '',
    billPartnerId: item.Bill_BPartner_ID?.id || '',
    billPartnerLocation: item.Bill_Location_ID || {},
    billPartnerLocationId: item.Bill_Location_ID?.id || '',
    organization: item.AD_Org_ID?.identifier || '',
    organizationId: item.AD_Org_ID?.id || '',
    client: item.AD_Client_ID?.identifier || '',
    clientId: item.AD_Client_ID?.id || '',
    orderSource: orderSource,
    orderSourceId: item.C_OrderSource_ID?.id || '',
    orderSourceName: item.order_source_name || item.C_OrderSource_ID?.identifier || '',
    externalorderId: item.ExternalOrderId || '',
    shopware6_order_id: item.shopware6_order_id || '',
    shopify_order_id: item.shopify_order_id || '',
    amazon_order_id: item.amazon_order_id || '',
    plentyone_order_id: item.plentyone_order_id || '',
    jtl_order_id: item.jtl_order_id || '',
    country: item.ship_country || '',
    countryCode: item.ship_countrycode?.id || '',
    countryId: '',
    locationStreet: item.ship_address1 || '',
    locationStreet2: item.ship_address2 || '',
    locationZipCode: item.ship_postal || '',
    locationCity: item.ship_city || '',
    name2: item.ship_name2 || '',
    location: { id: item.ship_location_id?.id || item.ship_location_id || null },
    minout: minout,
    shipperId: item.shipper_id || '',
    shipper: item.shipper_name || '',
    shipperName: item.shipper_name || '',
    shipperCfgIdentifier: item.shipper_cfg || '',
    isAttachmentRequired: item.is_attachment_required === true,
    isPrintDINA4: item.is_print_dina4 === true,
    paketTypeName: item.paket_type_name || '',
    shipmentWeight: item.shipment_weight || null,
    shippingDate: item.shipping_date || '',
    totalQty: item.TotalQty || 0,
    orderLines: [{ QtyEntered: item.TotalQty || 0 }],
    fulfillmentFeeTotal: item.fulfillment_fee_total || 0,
    feeProcessed: item.fee_processed === true || item.fee_processed === 'Y',
    feeEditable: (item.fulfillment_fee_total || 0) > 0 && !(item.fee_processed === true || item.fee_processed === 'Y'),
    daysSinceCreated: item.Created ? Math.floor((Date.now() - new Date(item.Created).getTime()) / 86400000) : 0,
    createdToOrderedAge: calculateAge(item.Created, item.DateOrdered),
    hasShipment: item.has_shipment === 'Y',
    hasInvoice: item.has_invoice === 'Y',
    hasDescription: item.has_description === 'Y',
    billingDiffersFromShipping: item.billing_differs_from_shipping === 'Y',
  }
}

const handleFunc = async (event: any, authToken: any = null) => {
  let data: any = { rows: [], lastRow: 0 }
  const token = authToken ?? await getTokenHelper(event)
  const body = await readBody(event)

  const startRow = body.startRow || 0
  const endRow = body.endRow || 100
  const pageSize = endRow - startRow

  // Base filter
  let baseFilter = 'IsSOTrx eq true'

  // Custom switch filters
  if (body.orgId) {
    baseFilter += ` AND AD_Org_ID eq ${body.orgId}`
  }

  if (body.openOnly === true) {
    baseFilter += ` AND has_shipment eq 'N' AND (DocStatus eq 'CO' or DocStatus eq 'DR' or DocStatus eq 'IP')`
  }

  if (body.openShipments === true) {
    baseFilter += ` AND has_shipment eq 'Y' AND IsCommissioned eq false AND (DocStatus eq 'CO' or DocStatus eq 'DR' or DocStatus eq 'IP')`
  }

  if (body.shipped === true) {
    baseFilter += ` AND has_shipment eq 'Y' AND TrackingNo gt '' AND (DocStatus eq 'CO' or DocStatus eq 'IP')`
  }

  if (body.noFees === true) {
    baseFilter += ` AND fulfillment_fee_total eq 0`
  }

  // Shipper filter
  if (body.shipperId) {
    baseFilter += ` AND shipper_id eq ${body.shipperId}`
  }

  // Order source filter
  if (body.orderSourceId) {
    baseFilter += ` AND C_OrderSource_ID eq ${body.orderSourceId}`
  }

  // Marketplace filter (TODO: fix filtering)
  // if (body.marketplaceName) {
  //   baseFilter += ` AND marketplace_name eq '${body.marketplaceName}'`
  // }

  // Created date filter — filters on c_order.Created only
  if (body.dateFrom || body.dateTo) {
    if (body.dateFrom) {
      baseFilter += ` AND Created ge ${body.dateFrom}`
    }
    if (body.dateTo) {
      const nextDay = new Date(body.dateTo + 'T00:00:00')
      nextDay.setDate(nextDay.getDate() + 1)
      const nextDayStr = `${nextDay.getFullYear()}-${String(nextDay.getMonth() + 1).padStart(2, '0')}-${String(nextDay.getDate()).padStart(2, '0')}`
      baseFilter += ` AND Created lt ${nextDayStr}`
    }
  }

  // Shipped date filter — filters on shipping_date only
  if (body.shippedDateFrom || body.shippedDateTo) {
    if (body.shippedDateFrom) {
      baseFilter += ` AND shipping_date ge ${body.shippedDateFrom}`
    }
    if (body.shippedDateTo) {
      const nextDay = new Date(body.shippedDateTo + 'T00:00:00')
      nextDay.setDate(nextDay.getDate() + 1)
      const nextDayStr = `${nextDay.getFullYear()}-${String(nextDay.getMonth() + 1).padStart(2, '0')}-${String(nextDay.getDate()).padStart(2, '0')}`
      baseFilter += ` AND shipping_date lt ${nextDayStr}`
    }
  }

  // AG Grid column filters
  const agFilter = filterHandler(body.filterModel || {})

  const fullFilter = baseFilter + agFilter
  const sortClause = buildSortClause(body.sortModel)
  console.log('[summary] fullFilter:', fullFilter)

  const [res, sumRes]: any[] = await Promise.all([
    event.context.fetch(
      `models/v_orders_summary?$filter=${string.urlEncode(fullFilter)}&$orderby=${string.urlEncode(sortClause)}&$top=${pageSize}&$skip=${startRow}`,
      'GET', token, null
    ),
    event.context.fetch(
      `models/v_orders_summary?$filter=${string.urlEncode(fullFilter)}&$select=fulfillment_fee_total,GrandTotal&$top=999999`,
      'GET', token, null
    ),
  ])

  if (res) {
    // If DocStatus is missing (limited role permission issue), fetch via service token
    const config = useRuntimeConfig()
    const serviceToken = config.api.idempieretoken
    let serviceDocStatusMap: Record<number, any> = {}
    const records = res.records || []
    const ordersMissingDocStatus = records.filter((item: any) => !item.DocStatus)
    if (ordersMissingDocStatus.length > 0 && serviceToken) {
      const orderIds = ordersMissingDocStatus.map((item: any) => item.id)
      const idsFilter = orderIds.map((id: number) => `C_Order_ID eq ${id}`).join(' OR ')
      try {
        const serviceRes: any = await fetchHelper(event, `models/c_order?$filter=${string.urlEncode(idsFilter)}&$select=DocStatus&$top=${orderIds.length}`, 'GET', serviceToken, null)
        if (serviceRes?.records) {
          for (const rec of serviceRes.records) {
            serviceDocStatusMap[rec.id] = rec.DocStatus
          }
        }
      } catch (e) {
        // Silently continue — status tags will be missing but grid still works
      }
    }

    data.rows = records.map((item: any) => mapRow(item, serviceDocStatusMap[item.id]))
    data.lastRow = res['row-count'] || 0
  }

  if (sumRes?.records) {
    data.totalFees = sumRes.records.reduce((sum: number, r: any) => sum + (r.fulfillment_fee_total || 0), 0)
    data.totalGrandTotal = sumRes.records.reduce((sum: number, r: any) => sum + (r.GrandTotal || 0), 0)
  }

  return data
}

export default defineEventHandler(async (event) => {
  let data: any = {}

  try {
    data = await handleFunc(event)
  } catch (err: any) {
    try {
      const authToken: any = await refreshTokenHelper(event)
      data = await handleFunc(event, authToken)
    } catch (error: any) {
      data = errorHandlingHelper(err?.data ?? err, error?.data ?? error)
    }
  }

  return data
})
