package com.ffii.fpsms.modules.stock.trace

import com.ffii.core.support.JdbcDao
import com.ffii.fpsms.modules.stock.web.model.*
import org.springframework.stereotype.Component

@Component
open class TraceExtendedLoader(
    private val jdbcDao: JdbcDao,
    private val sql: TraceSqlSupport,
) {
    open fun loadFailEvents(inventoryLotId: Long): List<ItemLotTraceFailEvent> {
        val query = """
            SELECT
                f.id AS failId,
                COALESCE(f.type, '') AS failType,
                COALESCE(f.category, '') AS category,
                COALESCE(f.qty, 0) AS qty,
                COALESCE(u.name, '') AS handlerName,
                f.recordDate AS recordDate,
                COALESCE(po.code, '') AS pickOrderCode,
                po.id AS pickOrderId,
                COALESCE(wh.code, '') AS warehouseCode
            FROM fail_inventory_lot_line f
            LEFT JOIN user u ON f.handerId = u.id AND u.deleted = 0
            LEFT JOIN stock_out_line sol ON f.stock_out_line_id = sol.id AND sol.deleted = 0
            LEFT JOIN pick_order_line pol ON sol.pickOrderLineId = pol.id AND pol.deleted = 0
            LEFT JOIN pick_order po ON pol.poId = po.id AND po.deleted = 0
            LEFT JOIN inventory_lot_line ill ON sol.inventoryLotLineId = ill.id AND ill.deleted = 0
            LEFT JOIN warehouse wh ON ill.warehouseId = wh.id AND wh.deleted = 0
            WHERE f.deleted = 0 AND f.Lot_id = :inventoryLotId
            ORDER BY recordDate DESC, f.id DESC
        """.trimIndent()
        return jdbcDao.queryForList(query, mapOf("inventoryLotId" to inventoryLotId)).map { row ->
            ItemLotTraceFailEvent(
                failId = sql.longVal(row["failId"]) ?: 0L,
                failType = sql.str(row["failType"]),
                category = sql.str(row["category"]),
                qty = sql.decimal(row["qty"]),
                handlerName = sql.str(row["handlerName"]),
                recordDate = sql.formatDate(row["recordDate"]),
                pickOrderCode = sql.str(row["pickOrderCode"]),
                pickOrderId = sql.longVal(row["pickOrderId"]),
                warehouseCode = sql.str(row["warehouseCode"]),
            )
        }
    }

    open fun loadLotRelations(
        inventoryLotId: Long,
        itemId: Long,
        lotNo: String,
    ): List<ItemLotTraceLotRelation> {
        val query = """
            SELECT
                'REPACK_SIBLING' AS relationType,
                il2.id AS inventoryLotId,
                COALESCE(il2.lotNo, '') AS lotNo,
                COALESCE(it.code, '') AS itemCode,
                COALESCE(it.name, '') AS itemName,
                COALESCE(sil2.acceptedQty, 0) AS qty,
                COALESCE(sil_src.productLotNo, '') AS productLotNo,
                COALESCE(sil2.created, sil2.modified, sil2.receiptDate) AS timestamp
            FROM inventory_lot il
            INNER JOIN stock_in_line sil_src ON il.stockInLineId = sil_src.id AND sil_src.deleted = 0
            INNER JOIN stock_in_line sil2 ON sil2.deleted = 0
                AND sil2.itemId = il.itemId
                AND sil2.productLotNo IS NOT NULL
                AND TRIM(sil2.productLotNo) <> ''
                AND sil2.productLotNo = sil_src.productLotNo
            INNER JOIN inventory_lot il2 ON sil2.inventoryLotId = il2.id AND il2.deleted = 0
            INNER JOIN items it ON il2.itemId = it.id AND it.deleted = 0
            WHERE il.id = :inventoryLotId
              AND il.deleted = 0
              AND il2.id <> :inventoryLotId
              AND COALESCE(il2.lotNo, '') <> :lotNo
              AND sil2.purchaseOrderId IS NULL
              AND (
                  sil_src.purchaseOrderId IS NULL
                  OR sil2.stockTransferId IS NOT NULL
                  OR EXISTS (
                      SELECT 1
                      FROM stock_transfer_record tr
                      INNER JOIN stock_out_line sol ON tr.stockOutLineId = sol.id AND sol.deleted = 0
                      INNER JOIN inventory_lot_line ill ON sol.inventoryLotLineId = ill.id AND ill.deleted = 0
                      WHERE tr.stockInLineId = sil2.id
                        AND ill.inventoryLotId = il.id
                  )
                  OR (
                      sil2.jobOrderId IS NOT NULL
                      AND sil2.jobOrderId = sil_src.jobOrderId
                  )
              )
            ORDER BY timestamp, il2.lotNo
        """.trimIndent()
        return jdbcDao.queryForList(
            query,
            mapOf("inventoryLotId" to inventoryLotId, "lotNo" to lotNo),
        ).map { row ->
            ItemLotTraceLotRelation(
                relationType = sql.str(row["relationType"]),
                inventoryLotId = sql.longVal(row["inventoryLotId"]),
                lotNo = sql.str(row["lotNo"]),
                itemCode = sql.str(row["itemCode"]),
                itemName = sql.str(row["itemName"]),
                qty = sql.decimal(row["qty"]),
                productLotNo = sql.str(row["productLotNo"]),
                timestamp = sql.formatDateTime(row["timestamp"]),
            )
        }.distinctBy { "${it.itemCode}:${it.lotNo}" }
    }
}
