package com.ffii.fpsms.m18.service

import com.ffii.fpsms.api.service.ApiCallerService
import com.ffii.fpsms.m18.M18Config
import com.ffii.fpsms.m18.model.GoodsReceiptNoteRequest
import com.ffii.fpsms.m18.model.GoodsReceiptNoteResponse
import com.google.gson.Gson
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service
import org.springframework.util.LinkedMultiValueMap
import reactor.core.publisher.Mono

/**
 * Service to create Goods Receipt Note (AN) in M18 via the save API.
 * API: PUT http://[server]/jsf/rfws/root/api/save/an
 * Query: menuCode=an (required), param (optional, JSON string)
 * Headers: authorization (Bearer token), client_id
 */
@Service
open class M18GoodsReceiptNoteService(
    private val m18Config: M18Config,
    private val apiCallerService: ApiCallerService,
) {
    private val logger: Logger = LoggerFactory.getLogger(M18GoodsReceiptNoteService::class.java)

    private val M18_SAVE_GOODS_RECEIPT_NOTE_API = "/root/api/save/an"
    private val MENU_CODE_AN = "an"

    /**
     * Creates a goods receipt note in M18.
     *
     * @param request The request body containing mainan (header) and ant (lines).
     * @param param Optional extra parameters in JSON format (query param "param").
     * @return The M18 response with recordId, messages, and status; or null on failure.
     */
    open fun createGoodsReceiptNote(
        request: GoodsReceiptNoteRequest,
        param: String? = null,
    ): GoodsReceiptNoteResponse? {
        return createGoodsReceiptNoteMono(request, param).block()
    }

    /**
     * Creates a goods receipt note in M18 (reactive).
     *
     * @param request The request body containing mainan (header) and ant (lines).
     * @param param Optional extra parameters in JSON format (query param "param").
     * @return Mono of the M18 response.
     */
    open fun createGoodsReceiptNoteMono(
        request: GoodsReceiptNoteRequest,
        param: String? = null,
    ): Mono<GoodsReceiptNoteResponse> {
        val queryParams = LinkedMultiValueMap<String, String>().apply {
            add("menuCode", MENU_CODE_AN)
            param?.let { add("param", it) }
        }
        val queryString = queryParams.entries.flatMap { (k, v) -> v.map { value -> "$k=$value" } }.joinToString("&")
        val fullUrl = "${m18Config.BASE_URL}$M18_SAVE_GOODS_RECEIPT_NOTE_API?$queryString"
        val requestJson = Gson().toJson(request)
        logger.info("[M18 GRN API] call=PUT url=$fullUrl queryParams=$queryParams body=$requestJson")
        return apiCallerService.put<GoodsReceiptNoteResponse>(
            urlPath = M18_SAVE_GOODS_RECEIPT_NOTE_API,
            queryParams = queryParams,
            body = request,
        ).doOnSuccess { response ->
            val responseJson = Gson().toJson(response)
            logger.info("[M18 GRN API] response (all): $responseJson")
            if (response.status) {
                logger.info("Goods receipt note created in M18. recordId=${response.recordId}")
            } else {
                logger.warn("M18 save AN returned status=false. recordId=${response.recordId}, messages=${response.messages}")
            }
        }.doOnError { e ->
            logger.error("[M18 GRN API] call failed: $fullUrl error=${e.message}", e)
        }
    }
}
