import { Pool } from 'pg'
import refreshTokenHelper from "../../../utils/refreshTokenHelper"

// Auto-propose allocations for ONE PO↔SO pair (the confirm dialog that opens
// when an inbound truck is dropped onto an outbound truck on the board).
//
// Pairs the two orders' item lines by product (lines ranked per product on both
// sides and joined rank-to-rank), returns open quantities, what is already
// allocated elsewhere, and the existing allocation of THIS pair (for upsert).
// The proposed qty itself is computed client-side:
//   min(poOpen - poAllocatedOther, soOpen - soAllocatedOther), floored at 0.
//
// Query params: poOrderId, soOrderId (both required)
const handleFunc = async (event: any) => {
  const config = useRuntimeConfig()
  const dbConfig = {
    host: config.pgHost,
    port: parseInt(config.pgPort || '5432'),
    database: config.pgDatabase,
    user: config.pgUser,
    password: config.pgPassword,
  }

  if (!dbConfig.host || !dbConfig.database || !dbConfig.user || !dbConfig.password) {
    throw createError({
      statusCode: 500,
      message: 'PostgreSQL credentials not configured. Please set PG_HOST, PG_DATABASE, PG_USER, PG_PASSWORD in .env'
    })
  }

  const query = getQuery(event)
  const poOrderId = parseInt(String(query?.poOrderId || ''))
  const soOrderId = parseInt(String(query?.soOrderId || ''))
  if (!Number.isFinite(poOrderId) || !Number.isFinite(soOrderId)) {
    throw createError({ statusCode: 400, message: 'poOrderId and soOrderId are required' })
  }

  const pool = new Pool(dbConfig)

  try {
    // Unqualified + adempiere-schema check: iDempiere tables live in the
    // `adempiere` schema (resolved via search_path), NOT in `public`.
    const reg = await pool.query(
      `SELECT COALESCE(to_regclass('cust_crossdockalloc'), to_regclass('adempiere.cust_crossdockalloc')) AS t`
    )
    if (!reg.rows?.[0]?.t) {
      return { rows: [], linkTableMissing: true }
    }

    const sql = `
      WITH po_lines AS (
        SELECT ol.c_orderline_id, ol.m_product_id, ol.line,
               (ol.qtyordered - COALESCE(ol.qtydelivered, 0)) AS open_qty,
               ROW_NUMBER() OVER (PARTITION BY ol.m_product_id ORDER BY ol.line, ol.c_orderline_id) AS rn
        FROM c_orderline ol
        JOIN m_product p ON p.m_product_id = ol.m_product_id AND p.producttype = 'I'
        WHERE ol.c_order_id = $1
      ),
      so_lines AS (
        SELECT ol.c_orderline_id, ol.m_product_id, ol.line,
               (ol.qtyordered - COALESCE(ol.qtydelivered, 0)) AS open_qty,
               ROW_NUMBER() OVER (PARTITION BY ol.m_product_id ORDER BY ol.line, ol.c_orderline_id) AS rn
        FROM c_orderline ol
        JOIN m_product p ON p.m_product_id = ol.m_product_id AND p.producttype = 'I'
        WHERE ol.c_order_id = $2
      ),
      alloc_po AS (
        SELECT po_orderline_id, SUM(qtyallocated) AS qty
        FROM cust_crossdockalloc WHERE isactive = 'Y' GROUP BY po_orderline_id
      ),
      alloc_so AS (
        SELECT so_orderline_id, SUM(qtyallocated) AS qty
        FROM cust_crossdockalloc WHERE isactive = 'Y' GROUP BY so_orderline_id
      ),
      pair_alloc AS (
        SELECT po_orderline_id, so_orderline_id,
               MIN(cust_crossdockalloc_id) AS id,
               SUM(qtyallocated) AS qty
        FROM cust_crossdockalloc WHERE isactive = 'Y'
        GROUP BY po_orderline_id, so_orderline_id
      )
      SELECT p.name  AS product_name,
             p.value AS sku,
             pl.m_product_id,
             pl.c_orderline_id AS po_orderline_id,
             sl.c_orderline_id AS so_orderline_id,
             pl.open_qty AS po_open_qty,
             sl.open_qty AS so_open_qty,
             COALESCE(ap.qty, 0)  AS po_allocated_total,
             COALESCE(aso.qty, 0) AS so_allocated_total,
             pa.id AS existing_id,
             COALESCE(pa.qty, 0) AS existing_qty
      FROM po_lines pl
      JOIN so_lines sl ON sl.m_product_id = pl.m_product_id AND sl.rn = pl.rn
      LEFT JOIN m_product p    ON p.m_product_id = pl.m_product_id
      LEFT JOIN alloc_po ap    ON ap.po_orderline_id = pl.c_orderline_id
      LEFT JOIN alloc_so aso   ON aso.so_orderline_id = sl.c_orderline_id
      LEFT JOIN pair_alloc pa  ON pa.po_orderline_id = pl.c_orderline_id
                              AND pa.so_orderline_id = sl.c_orderline_id
      ORDER BY p.name, pl.line
    `
    const result = await pool.query(sql, [poOrderId, soOrderId])

    const rows = result.rows.map((r: any) => {
      const poOpen = parseFloat(r.po_open_qty || 0)
      const soOpen = parseFloat(r.so_open_qty || 0)
      const existingQty = parseFloat(r.existing_qty || 0)
      // "allocated elsewhere" excludes what THIS pair already holds.
      const poAllocatedOther = Math.max(0, parseFloat(r.po_allocated_total || 0) - existingQty)
      const soAllocatedOther = Math.max(0, parseFloat(r.so_allocated_total || 0) - existingQty)
      return {
        productId: Number(r.m_product_id),
        productName: r.product_name || '',
        sku: r.sku || '',
        poOrderLineId: Number(r.po_orderline_id),
        soOrderLineId: Number(r.so_orderline_id),
        poOpenQty: poOpen,
        soOpenQty: soOpen,
        poAllocatedOther,
        soAllocatedOther,
        existingId: r.existing_id ? Number(r.existing_id) : null,
        existingQty
      }
    })

    return { rows, linkTableMissing: false }
  } catch (err: any) {
    console.error('PostgreSQL query error (crossdock match-proposal):', err)
    throw createError({ statusCode: 500, message: `Database error: ${err.message}` })
  } finally {
    await pool.end()
  }
}

export default defineEventHandler(async (event) => {
  try {
    return await handleFunc(event)
  } catch (err: any) {
    try {
      await refreshTokenHelper(event)
      return await handleFunc(event)
    } catch (error: any) {
      console.error('Fatal error in crossdock match-proposal:', error)
      throw error
    }
  }
})
