package com.ffii.fpsms.modules.report.service

import com.ffii.core.support.JdbcDao
import org.springframework.stereotype.Service

@Service
class MaterialStockOutTraceabilityReportService(
    private val jdbcDao: JdbcDao,
) {
    fun getDistinctHandlersForMaterialStockOutTraceability(): List<String> {
        val sql = """
        SELECT DISTINCT COALESCE(picker_user.name, jpo_handler_user.name, created_user.name, modified_user.name, '') AS handler
        FROM stock_out_line sol
        INNER JOIN stock_out so ON sol.stockOutId = so.id AND so.deleted = 0 AND so.type = 'job'
        INNER JOIN pick_order_line pol ON sol.pickOrderLineId = pol.id AND pol.deleted = 0
        INNER JOIN pick_order po ON pol.poId = po.id AND po.deleted = 0 AND po.type IN ('jo', 'JOB_ORDER') AND po.joId IS NOT NULL
        LEFT JOIN user picker_user ON sol.handled_by = picker_user.id AND picker_user.deleted = 0
        LEFT JOIN jo_pick_order jpo ON po.id = jpo.pick_order_id AND pol.itemId = jpo.item_id AND jpo.deleted = 0
        LEFT JOIN user jpo_handler_user ON jpo.handled_by = jpo_handler_user.id AND jpo_handler_user.deleted = 0
        LEFT JOIN user created_user ON sol.createdBy = created_user.username AND created_user.deleted = 0
        LEFT JOIN user modified_user ON sol.modifiedBy = modified_user.staffNo AND modified_user.deleted = 0 AND sol.handled_by IS NULL
        WHERE sol.deleted = 0
        ORDER BY handler
    """.trimIndent()

        return jdbcDao
            .queryForList(sql, emptyMap<String, Any>())
            .map { row -> (row["handler"]?.toString() ?: "").trim() }
            .filter { it.isNotBlank() }
    }

    fun searchMaterialStockOutTraceabilityReport(
        stockCategory: String?,
        stockSubCategory: String?,
        itemCode: String?,
        year: String?,
        lastOutDateStart: String?,
        lastOutDateEnd: String?,
        handler: String?,
    ): List<Map<String, Any>> {
        val args = mutableMapOf<String, Any>()

        // Stock Category filtering (items.type)
        val stockCategorySql = buildMultiValueExactClause(
            stockCategory,
            "it.type",
            "stockCategory",
            args,
        )

        // Keep as-is (no filter yet)
        val stockSubCategorySql = ""

        val itemCodeSql = buildMultiValueLikeClause(
            itemCode,
            "it.code",
            "itemCode",
            args,
        )

        // Filter by sol.endTime year
        val yearSql = if (!year.isNullOrBlank()) {
            args["year"] = year
            "AND YEAR(sol.endTime) = :year"
        } else ""

        val lastOutDateStartSql = if (!lastOutDateStart.isNullOrBlank()) {
            val formattedDate = lastOutDateStart.replace("/", "-")
            args["lastOutDateStart"] = formattedDate
            "AND DATE(sol.endTime) >= DATE(:lastOutDateStart)"
        } else ""

        val lastOutDateEndSql = if (!lastOutDateEnd.isNullOrBlank()) {
            val formattedDate = lastOutDateEnd.replace("/", "-")
            args["lastOutDateEnd"] = formattedDate
            "AND DATE(sol.endTime) <= DATE(:lastOutDateEnd)"
        } else ""

        val handlerSql = buildMultiValueExactClause(
            handler,
            "COALESCE(picker_user.name, jpo_handler_user.name, created_user.name, modified_user.name, '')",
            "handler",
            args,
        )

        val sql = """
          SELECT
         IFNULL(it.code, '')                                AS itemNo,
         IFNULL(it.name, '')                                AS itemName,
         IFNULL(it.categoryId, 0)                           AS stockSubCategory,
         IFNULL(uc.udfudesc, '')                            AS unitOfMeasure,
         IFNULL(jo.code, '')                               AS jobOrderNo,
         IFNULL(po.consoCode, '')                           AS stockReqNo,
         IFNULL(il.lotNo, '')                               AS lotNo,
         IFNULL(DATE_FORMAT(il.expiryDate, '%Y-%m-%d'), '') AS expiryDate,
         FORMAT(ROUND(IFNULL(sol.qty, 0), 0), 0)           AS stockOutQty,
         IFNULL(po.code, '')                                AS materialPickOrderNo,
         COALESCE(
             picker_user.name,
             jpo_handler_user.name,
             created_user.name,
             modified_user.name,
             ''
         )                                                  AS handler,
         COALESCE(wh.code, '')                              AS storeLocation,
         ''                                                 AS pickRemark,
         FORMAT(
             ROUND(SUM(IFNULL(sol.qty, 0)) OVER (PARTITION BY it.code), 0), 0
         )                                                  AS totalStockOutQty
         FROM stock_out_line sol
         INNER JOIN stock_out so
             ON sol.stockOutId = so.id
            AND so.deleted = 0
            AND so.type = 'job'
         INNER JOIN pick_order_line pol
             ON sol.pickOrderLineId = pol.id
            AND pol.deleted = 0
         INNER JOIN pick_order po
             ON pol.poId = po.id
            AND po.deleted = 0
            AND po.type IN ('jo', 'JOB_ORDER')
            AND po.joId IS NOT NULL
         LEFT JOIN job_order jo
             ON po.joId = jo.id
            AND jo.deleted = 0
         INNER JOIN items it
             ON sol.itemId = it.id
            AND it.deleted = 0
         LEFT JOIN item_uom iu
             ON it.id = iu.itemId
            AND iu.stockUnit = 1
         LEFT JOIN uom_conversion uc
             ON iu.uomId = uc.id
         LEFT JOIN inventory_lot_line ill
             ON sol.inventoryLotLineId = ill.id
            AND ill.deleted = 0
         LEFT JOIN inventory_lot il
             ON ill.inventoryLotId = il.id
            AND il.deleted = 0
         LEFT JOIN warehouse wh
             ON ill.warehouseId = wh.id
            AND wh.deleted = 0
         LEFT JOIN user picker_user
             ON sol.handled_by = picker_user.id
            AND picker_user.deleted = 0
         LEFT JOIN jo_pick_order jpo
             ON po.id = jpo.pick_order_id
            AND pol.itemId = jpo.item_id
            AND jpo.deleted = 0
              LEFT JOIN user jpo_handler_user
             ON jpo.handled_by = jpo_handler_user.id
            AND jpo_handler_user.deleted = 0
         LEFT JOIN user created_user
             ON sol.createdBy = created_user.username
            AND created_user.deleted = 0
         LEFT JOIN user modified_user
             ON sol.modifiedBy = modified_user.staffNo
            AND modified_user.deleted = 0
            AND sol.handled_by IS NULL
            WHERE
         sol.deleted = 0
         AND (sol.inventoryLotLineId IS NULL OR ill.id IS NOT NULL)
         $stockCategorySql
         $stockSubCategorySql
         $itemCodeSql
         $yearSql
         $lastOutDateStartSql
         $lastOutDateEndSql
         $handlerSql
     ORDER BY
         it.code,
         il.lotNo,
         sol.endTime
        """.trimIndent()

        val result = jdbcDao.queryForList(sql, args)

        println("=== Material Stock Out Traceability (Total: ${result.size} rows) ===")
        result.take(50).forEachIndexed { index, row ->
            println("Row $index:")
            println("  itemNo: ${row["itemNo"]}")
            println("  itemName: ${row["itemName"]}")
            println("  jobOrderNo: ${row["jobOrderNo"]}")
            println("  stockOutQty: ${row["stockOutQty"]}")
            println("  totalStockOutQty: ${row["totalStockOutQty"]}")
            println("  materialPickOrderNo: ${row["materialPickOrderNo"]}")
            println("  handler: ${row["handler"]}")
            println("  storeLocation: ${row["storeLocation"]}")
            println("  ---")
        }

        return result
    }

    private fun buildMultiValueLikeClause(
        paramValue: String?,
        columnName: String,
        paramPrefix: String,
        args: MutableMap<String, Any>,
    ): String {
        if (paramValue.isNullOrBlank()) return ""

        val values = paramValue.split(",").map { it.trim() }.filter { it.isNotBlank() }
        if (values.isEmpty()) return ""

        val conditions = values.mapIndexed { index, value ->
            val paramName = "${paramPrefix}_$index"
            args[paramName] = "%$value%"
            "$columnName LIKE :$paramName"
        }

        return "AND (${conditions.joinToString(" OR ")})"
    }

    private fun buildMultiValueExactClause(
        paramValue: String?,
        columnName: String,
        paramPrefix: String,
        args: MutableMap<String, Any>,
    ): String {
        if (paramValue.isNullOrBlank()) return ""

        val values = paramValue.split(",").map { it.trim() }.filter { it.isNotBlank() }
        if (values.isEmpty()) return ""

        val conditions = values.mapIndexed { index, value ->
            val paramName = "${paramPrefix}_$index"
            args[paramName] = value
            "$columnName = :$paramName"
        }

        return "AND (${conditions.joinToString(" OR ")})"
    }
}

