package com.ffii.fpsms.m18.service

import com.ffii.core.utils.JwtTokenUtil
import com.ffii.fpsms.api.service.ApiCallerService
import com.ffii.fpsms.m18.M18Config
import com.ffii.fpsms.m18.model.M18PurchaseQuotationListRequest
import com.ffii.fpsms.m18.model.M18PurchaseQuotationListResponse
import com.ffii.fpsms.m18.model.M18PurchaseQuotationRequest
import com.ffii.fpsms.m18.model.M18PurchaseQuotationResponse
import com.ffii.fpsms.m18.utils.CommonUtils
import com.ffii.fpsms.modules.master.service.ItemUomService
import com.ffii.fpsms.modules.master.service.ItemsService
import com.ffii.fpsms.modules.purchaseQuotation.service.PurchaseQuotationLineService
import com.ffii.fpsms.modules.purchaseQuotation.service.PurchaseQuotationService
import com.ffii.fpsms.modules.purchaseQuotation.web.model.SavePurchaseQuotationLineRequest
import com.ffii.fpsms.modules.purchaseQuotation.web.model.SavePurchaseQuotationRequest
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.stereotype.Service

@Service
open class M18PurchaseQuotationService(
    val m18Config: M18Config,
    val apiCallerService: ApiCallerService,
    val itemsService: ItemsService,
    val purchaseQuotationService: PurchaseQuotationService,
    val purchaseQuotationLineService: PurchaseQuotationLineService,
    val itemUomService: ItemUomService,
) {
    val commonUtils = CommonUtils()
    val logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)

    val lastModifyDateStart = "2025-05-14 14:00:00"
    val lastModifyDateEnd = "2025-05-14 14:30:00"
    val lastModifyDateConds =
        "lastModifyDate=largerOrEqual=${lastModifyDateStart}=and=lastModifyDate=lessOrEqual=${lastModifyDateEnd}"

    // M18 Conditions
    val beIdList = listOf(m18Config.BEID_PF, m18Config.BEID_PP, m18Config.BEID_TOA)
    val beIdConds = "(" + commonUtils.listToString(beIdList.filterNotNull(), "beId=equal=", "=or=") + ")"

    // M18 API
    val M18_LOAD_PURCHASE_QUOTATION_API = "/root/api/read/vqu"
    val M18_FETCH_PURCHASE_QUOTATION_LIST_API = "/search/search"

    open fun getPurchaseQuotations(): M18PurchaseQuotationListResponse? {
        val params = M18PurchaseQuotationListRequest(
            conds = beIdConds
        )

        var purchaseQuotations: M18PurchaseQuotationListResponse? = null

        try {
            purchaseQuotations =
                apiCallerService.get<M18PurchaseQuotationListResponse, M18PurchaseQuotationListRequest>(
                    M18_FETCH_PURCHASE_QUOTATION_LIST_API,
                    params
                ).block()
        } catch (e: Exception) {
            logger.error("(Getting Purchase Quotation list) Error on Function - ${e.stackTrace}")
            logger.error(e.message)
        }

        return purchaseQuotations
    }

    open fun getPurchaseQuotation(id: Long): M18PurchaseQuotationResponse? {
        val params = M18PurchaseQuotationRequest(
            id = id
        )

        var purchaseQuotation: M18PurchaseQuotationResponse? = null

        try {
            purchaseQuotation = apiCallerService.get<M18PurchaseQuotationResponse, M18PurchaseQuotationRequest>(
                M18_LOAD_PURCHASE_QUOTATION_API,
                params
            ).block()
        } catch (e: Exception) {
            logger.error("(Getting Purchase Quotation Detail) Error on Function - ${e.stackTrace}")
            logger.error(e.message)
        }

        return purchaseQuotation
    }

    open fun savePurchaseQuotations() {
        logger.info("--------------------------------------------Start - Saving M18 Purchase Quotations--------------------------------------------")
        val purchaseQuotations = getPurchaseQuotations()

        val pqRefType = "Purchase Quotation"
        val pqLineRefType = "Purchase Quotation Line"

        val successList = mutableListOf<Long>()
        val successDetailList = mutableListOf<Long>()
        val failList = mutableListOf<Long>()
        val failDetailList = mutableListOf<Long>()

        val values = purchaseQuotations?.values
        val pqsMessages = purchaseQuotations?.messages?.get(0)

        if (values != null) {
            values.forEach { purchaseQuotation ->
                try {
                    val pqDetail = getPurchaseQuotation(purchaseQuotation.id)
                    val mainvqu = if(pqDetail?.data?.mainvqu?.isNotEmpty() == true) pqDetail.data.mainvqu[0] else null
                    val remvqu = if(pqDetail?.data?.remvqu?.isNotEmpty() == true) pqDetail.data.remvqu[0] else null
                    val vqut = if(pqDetail?.data?.vqut?.isNotEmpty() == true) pqDetail.data.vqut else null
                    val pqMessages = if(pqDetail?.messages?.isNotEmpty() == true) pqDetail.messages[0] else null

                    var pqId: Long? = null

                    if (mainvqu != null) {
                        // Save Purchase Quotation
                        try {
                            val savePqRequest = SavePurchaseQuotationRequest(
                                code = mainvqu.code,
                                expiryDate = commonUtils.timestampToLocalDateTime(mainvqu.expDate),
                                effectiveDate = commonUtils.timestampToLocalDateTime(mainvqu.tDate),
                                m18ShopId = mainvqu.venId,
                                m18CurrencyId = mainvqu.curId,
                                remarks = remvqu?.remarks,
                                m18Id = mainvqu.id,
                                m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainvqu.lastModifyDate)
                            )

                            pqId = purchaseQuotationService.savePurchaseQuotation(savePqRequest).id
                            successList += mainvqu.id
                            logger.info("${pqRefType}: Saved purchase quotation. ID: ${pqId} | M18 ID: ${purchaseQuotation.id}")
                        } catch (e: Exception) {
                            failList.add(mainvqu.id)
                            logger.error("${pqRefType}: Saving Failure!")
                            logger.error("Error on Function - ${e.stackTrace} | Type: ${pqRefType} | M18 ID: ${purchaseQuotation.id}")
                            logger.error(e.message)
                        }

                        // Save Purchase Quotation Line
                        if (vqut != null) {
                            vqut.forEach { line ->
                                try {
                                    val savePqLineRequest = SavePurchaseQuotationLineRequest(
                                        purchaseQuotationId = pqId,
                                        m18ItemId = line.proId,
                                        code = line.refCode,
                                        description = line.bDesc,
                                        m18Id = line.id,
                                        m18LastModifyDate = commonUtils.timestampToLocalDateTime(mainvqu.lastModifyDate)
                                    )

                                    val pqLineId = purchaseQuotationLineService.savePurchaseQuotationLine(savePqLineRequest).id
                                    successDetailList += line.id
                                    logger.info("${pqRefType}: Saved purchase quotation line. ID: ${pqLineId} | M18 ID: ${purchaseQuotation.id} | M18 Line ID: ${line.id}")
                                } catch (e: Exception) {
                                    failDetailList.add(line.id)
                                    logger.error("${pqLineRefType}: Saving Failure!")
                                    logger.error("Error on Function - ${e.stackTrace} | Type: ${pqLineRefType} | M18 ID: ${purchaseQuotation.id} | M18 Line ID: ${line.id}")
                                    logger.error(e.message)
                                }
                            }
                        } else {
                            logger.error("Purchase Quotation Line is null. May occur errors.")
                        }
                    } else {
                        logger.error("Purchase Quotation is null. May occur errors.")
                        logger.error("Error code: ${pqMessages?.msgDetail}")
                        logger.error("Error messages: ${pqMessages?.msgDetail}")
                    }
                } catch (e: Exception) {
                    failList.add(purchaseQuotation.id)
                    logger.error("${pqRefType} / ${pqLineRefType}: Saving Failure!")
                    logger.error("Error on Function - ${e.stackTrace} | Type: ${pqRefType} / ${pqLineRefType} | M18 ID: ${purchaseQuotation.id}")
                    logger.error(e.message)
                }
            }
        } else {
            logger.error("Purchase Quotation List is null. May occur errors.")
            logger.error("Error code: ${pqsMessages?.msgDetail}")
            logger.error("Error messages: ${pqsMessages?.msgDetail}")
        }

        logger.info("Total Purchase Quotation Save Success (${successList.size})")
        logger.info("Total Purchase Quotation Save Detail Success (${successDetailList.size})")

        if (failList.size > 0) {
            logger.error("Total Purchase Quotation Fail (${failList.size}): $failList")
        }

        if (failDetailList.size > 0) {
            logger.error("Total Purchase Quotation Detail Fail (${failDetailList.size}): $failDetailList")
        }
        logger.info("--------------------------------------------End - Saving M18 Purchase Quotations--------------------------------------------")
    }
}