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

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'
    })
  }

  // Limited roles (FrontendMenu == 'c') only see their own organization. Admins
  // see all orgs (NULL filter is a no-op in the SQL below).
  const roleCookie = getCookie(event, 'logship_role')
  let menuType: string = 'Menu'
  try {
    const role = roleCookie ? JSON.parse(roleCookie) : null
    menuType = role?.FrontendMenu?.id || role?.FrontendMenu || 'Menu'
  } catch {}
  const orgIdCookie = getCookie(event, 'logship_organization_id')
  const orgIdNum = orgIdCookie ? parseInt(orgIdCookie) : NaN
  const orgFilter: number | null = (menuType === 'c' && Number.isFinite(orgIdNum)) ? orgIdNum : null

  const pool = new Pool(dbConfig)

  try {
    const sql = `
      WITH warehouse_stock AS (
        SELECT s.m_product_id,
               l.m_warehouse_id,
               SUM(s.qtyonhand) AS qtyonhand
        FROM m_storage s
        JOIN m_locator l ON l.m_locator_id = s.m_locator_id
        LEFT JOIN m_locatortype lt ON lt.m_locatortype_id = l.m_locatortype_id
        WHERE lt.m_locatortype_id IS NULL
           OR lt.isavailableforshipping = 'Y'
           OR lt.isavailableforreplenishment = 'Y'
           OR lt.isavailableforreservation = 'Y'
        GROUP BY s.m_product_id, l.m_warehouse_id
      ),
      total_stock AS (
        SELECT s.m_product_id, SUM(s.qtyonhand) AS qtyonhand
        FROM m_storage s
        JOIN m_locator l ON l.m_locator_id = s.m_locator_id
        LEFT JOIN m_locatortype lt ON lt.m_locatortype_id = l.m_locatortype_id
        WHERE lt.m_locatortype_id IS NULL
           OR lt.isavailableforshipping = 'Y'
           OR lt.isavailableforreplenishment = 'Y'
           OR lt.isavailableforreservation = 'Y'
        GROUP BY s.m_product_id
      )
      SELECT
        p.m_product_id AS id,
        p.name,
        p.value,
        p.sku,
        p.isbom,
        p.isjtlbom,
        p.strapi_product_documentid AS strapi_product_documentid,
        COUNT(DISTINCT o.c_order_id) AS order_count,
        SUM(ol.qtyordered - COALESCE(ol.qtydelivered, 0)) AS qty_needed,
        COALESCE(MAX(ts.qtyonhand), 0) AS qty_on_hand,
        GREATEST(
          SUM(ol.qtyordered - COALESCE(ol.qtydelivered, 0)) - COALESCE(MAX(ts.qtyonhand), 0),
          0
        ) AS qty_missing,
        ARRAY_AGG(DISTINCT COALESCE(org.name, 'Unknown')) AS org_names
      FROM c_order o
      JOIN c_orderline ol ON ol.c_order_id = o.c_order_id
      JOIN m_product p ON p.m_product_id = ol.m_product_id
      LEFT JOIN ad_org org ON org.ad_org_id = o.ad_org_id
      LEFT JOIN warehouse_stock ws
        ON ws.m_product_id = ol.m_product_id
       AND ws.m_warehouse_id = o.m_warehouse_id
      LEFT JOIN total_stock ts
        ON ts.m_product_id = ol.m_product_id
      WHERE o.issotrx = 'Y'
        AND o.docstatus IN ('CO','CL')
        AND o.ad_client_id = 1000000
        AND o.isfulfillmentorder = 'Y'
        AND ($1::int IS NULL OR o.ad_org_id = $1)
        AND ol.m_product_id IS NOT NULL
        AND p.producttype = 'I'
        AND (ol.qtyordered - COALESCE(ol.qtydelivered, 0)) > 0
        AND NOT EXISTS (
              SELECT 1
              FROM m_inout io
              JOIN m_inoutline iol ON iol.m_inout_id = io.m_inout_id
              WHERE io.c_order_id = o.c_order_id
                AND io.issotrx = 'Y'
                AND io.docstatus NOT IN ('VO','RE')
        )
      GROUP BY p.m_product_id, p.name, p.value, p.sku, p.isbom, p.isjtlbom, p.strapi_product_documentid
      -- Missing = SUMMED open demand exceeds stock. A per-line comparison here
      -- (the previous version) missed products whose demand is split across
      -- several lines/orders each individually below stock — e.g. one order
      -- with 3 lines of 15+40+40 = 95 needed vs 88 on hand was NOT listed.
      -- The BOOL_OR keeps the old per-line warehouse check as a safety net for
      -- demand sitting in a warehouse that has no stock of the product.
      HAVING SUM(ol.qtyordered - COALESCE(ol.qtydelivered, 0)) > COALESCE(MAX(ts.qtyonhand), 0)
          OR BOOL_OR((ol.qtyordered - COALESCE(ol.qtydelivered, 0)) > COALESCE(ws.qtyonhand, 0))
      ORDER BY qty_missing DESC, qty_needed DESC
      LIMIT 50
    `

    const result = await pool.query(sql, [orgFilter])

    const records = result.rows.map((r: any) => ({
      id: Number(r.id),
      name: r.name,
      value: r.value,
      sku: r.sku,
      isBom: r.isbom === 'Y',
      isJtlBom: r.isjtlbom === 'Y',
      strapiProductId: r.strapi_product_documentid || null,
      orderCount: parseInt(r.order_count || 0),
      qtyNeeded: parseFloat(r.qty_needed || 0),
      qtyOnHand: parseFloat(r.qty_on_hand || 0),
      qtyMissing: parseFloat(r.qty_missing || 0),
      orgNames: Array.isArray(r.org_names) ? r.org_names.filter(Boolean) : []
    }))

    return { records }
  } catch (err: any) {
    console.error('PostgreSQL query error:', 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 {
      let authToken: any = await refreshTokenHelper(event)
      return await handleFunc(event)
    } catch(error: any) {
      console.error('Fatal error in unfulfillable-products:', error)
      throw error
    }
  }
})
