package com.ffii.fpsms.modules.bag.service

import com.ffii.fpsms.modules.bag.entity.Bag
import com.ffii.fpsms.modules.bag.entity.BagLotLine
import com.ffii.fpsms.modules.bag.entity.JoBagConsumption
import org.springframework.stereotype.Service
import com.ffii.fpsms.modules.bag.web.model.*
import com.ffii.fpsms.modules.bag.entity.BagRepository
import com.ffii.fpsms.modules.bag.entity.BagLotLineRepository
import com.ffii.fpsms.modules.bag.entity.JoBagConsumptionRepository
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.stock.entity.InventoryLotRepository
import java.time.LocalTime
import java.time.LocalDateTime
import java.time.LocalDate
import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository
import com.ffii.fpsms.modules.productProcess.entity.ProductProcessRepository
import com.ffii.fpsms.modules.master.entity.ItemUomRespository
import java.math.BigDecimal
@Service
open class BagService(
    private val bagRepository: BagRepository,
    private val bagLotLineRepository: BagLotLineRepository,
    private val joBagConsumptionRepository: JoBagConsumptionRepository,
    private val inventoryLotRepository: InventoryLotRepository,
    private val jobOrderRepository: JobOrderRepository,
    private val productProcessRepository: ProductProcessRepository,
    private val itemUomRepository: ItemUomRespository,
) {
open fun createBagLotLinesByBagId(request: CreateBagLotLineRequest): MessageResponse {
    val bag = bagRepository.findById(request.bagId).orElse(null)
    val lot = inventoryLotRepository.findByIdAndDeletedFalse(request.lotId)
    val BaseUnitOfMeasure= itemUomRepository.findByItemIdAndStockUnitIsTrueAndDeletedIsFalse(request.itemId)
    val baseRatioN = BaseUnitOfMeasure?.ratioN ?: BigDecimal.ONE
    println("baseRatioN: $baseRatioN")
    val baseRatioD = BaseUnitOfMeasure?.ratioD ?: BigDecimal.ONE
    println("baseRatioD: $baseRatioD")
    val bagLotLine = BagLotLine().apply {
        this.bagId = bag?.id
        this.lotId = lot?.id
        this.lotNo = lot?.lotNo
        this.startQty = request.stockQty.toBigDecimal()
        .multiply(baseRatioN)
        .divide(baseRatioD)
        .toInt()
        println("startQty: $startQty")
        this.consumedQty = 0
        this.stockOutLineId = request.stockOutLineId
        this.scrapQty = 0
        this.balanceQty = request.stockQty.toBigDecimal()
            .multiply(baseRatioN)
            .divide(baseRatioD)
            .toInt()
        println("balanceQty: $balanceQty")
    }
    bagLotLineRepository.save(bagLotLine)
    bag.takenBagBalance = (bag.takenBagBalance ?: 0) + (bagLotLine.balanceQty ?: 0)
    bagRepository.save(bag)

    return MessageResponse(
        id = null,
        code = null,
        name = null,
        type = null,
        message = null,
        errorPosition = null,
        entity = null,
    )
}

fun createJoBagConsumption(request: CreateJoBagConsumptionRequest): MessageResponse {
    val bag = bagRepository.findById(request.bagId).orElse(null)
    println("bagId: ${bag?.id}")
    println(request.toString())
    if (bag == null) {
        return MessageResponse(
            id = null,
            code = null,
            name = null,
            type = "error",
            message = "Bag not found with id: ${request.bagId}",
            errorPosition = null,
            entity = null,
        )
    }

    val bagLotLine = bagLotLineRepository.findById(request.bagLotLineId).orElse(null)
    println("bagLotLineId: ${bagLotLine?.id}")
    if (bagLotLine == null) {
        return MessageResponse(
            id = null,
            code = null,
            name = null,
            type = "error",
            message = "BagLotLine not found with id: ${request.bagLotLineId}",
            errorPosition = null,
            entity = null,
        )
    }
    val balanceQty = bagLotLine.balanceQty ?: 0
    val startQty = bagLotLine.startQty ?: 0

    if (balanceQty < request.consumedQty + request.scrapQty) {
        return MessageResponse(
            id = null,
            code = null,
            name = null,
            type = "error",
            message = "Insufficient balance. Available: $balanceQty, Requested: ${request.consumedQty + request.scrapQty}",
            errorPosition = null,
            entity = null,
        )
    }

    val newBalanceQty = balanceQty - request.consumedQty - request.scrapQty
    if (bagLotLine.firstUseDate == null)
    {
        bagLotLine.firstUseDate = LocalDate.now()
        bagLotLineRepository.save(bagLotLine)
    }
    bagLotLine.consumedQty = (bagLotLine.consumedQty ?: 0) + request.consumedQty
    bagLotLine.scrapQty = (bagLotLine.scrapQty ?: 0) + request.scrapQty
    bagLotLine.balanceQty = newBalanceQty
    bagLotLine.lastUseDate = LocalDate.now()
    
    bagLotLineRepository.save(bagLotLine)

    val consumedTotal = request.consumedQty + request.scrapQty
    val jobOrder = jobOrderRepository.findById(request.jobId).orElse(null)
    bag.takenBagBalance = (bag.takenBagBalance ?: 0) - consumedTotal
    bagRepository.save(bag)

    val joBagConsumption = JoBagConsumption().apply {
        this.bagId = request.bagId
        this.bagLotLineId = request.bagLotLineId
        this.jobId = request.jobId
        this.stockOutLineId = bagLotLine.stockOutLineId
        this.jobOrderCode=jobOrder?.code?:""
        this.startQty = balanceQty
        this.consumedQty = request.consumedQty
        this.scrapQty = request.scrapQty
        this.endQty = newBalanceQty
        this.date = LocalDate.now()
        this.time = LocalDateTime.now()
    }
    joBagConsumptionRepository.save(joBagConsumption)
    
    // 更新 ProductProcess 的 submitedBagRecord 为 true
    val productProcesses = productProcessRepository.findByJobOrder_Id(request.jobId)
    productProcesses.forEach { productProcess ->
        productProcess.submitedBagRecord = true
        productProcessRepository.save(productProcess)
    }
    
    return MessageResponse(
        id = null,
        code = null,
        name = null,
        type = null,
        message = null,
        errorPosition = null,
        entity = null,
    )
}
    
open fun getAllBagInfo(): List<BagInfo> {
    val bags = bagRepository.findAllByDeletedIsFalse()
    return bags.flatMap { bag ->
        val bagLotLines = bagLotLineRepository.findAllByBagId(bag.id)
        bagLotLines.map { bagLotLine ->
            BagInfo(
                id = bagLotLine.id,
                bagId = bag.id,
                bagName = bag?.itemName?:"",
                lotId = bagLotLine.lotId ?: 0L,
                lotNo = bagLotLine.lotNo ?: "",
                stockOutLineId = bagLotLine.stockOutLineId ?: 0L,
                code = bag?.itemCode ?: "",
                balanceQty = bagLotLine.balanceQty ?: 0,
            )
        }
    }
}
open fun getAllBagUsageRecords(): List<BagUsageRecordResponse> {
    val allRecords = joBagConsumptionRepository.findAllByDeletedIsFalse()
    
    return allRecords.map { record ->
        val bag = bagRepository.findById(record.bagId ?: 0L).orElse(null)
        val bagLotLine = bagLotLineRepository.findById(record.bagLotLineId ?: 0L).orElse(null)
        
        BagUsageRecordResponse(
            id = record.id ?: 0L,
            bagId = record.bagId ?: 0L,
            bagLotLineId = record.bagLotLineId ?: 0L,
            jobId = record.jobId ?: 0L,
            jobOrderCode = record.jobOrderCode ?: "",
            stockOutLineId = record.stockOutLineId ?: 0L,
            startQty = record.startQty ?: 0,
            consumedQty = record.consumedQty ?: 0,
            scrapQty = record.scrapQty ?: 0,
            endQty = record.endQty ?: 0,
            date = record.date ?: LocalDate.now(),
            time = record.time ?: LocalDateTime.now(),
            bagName = bag?.itemName,
            bagCode = bag?.itemCode,
            lotNo = bagLotLine?.lotNo
        )
    }
}

open fun getBagSummaries(): List<BagSummaryResponse> {
    return bagRepository.findAllByDeletedIsFalse().map { bag ->
        BagSummaryResponse(
            id = bag.id ?: 0L,
            bagName = bag.itemName,
            bagCode = bag.itemCode,
            takenBagBalance = bag.takenBagBalance,
            deleted = bag.deleted
        )
    }
}

open fun getBagLotLines(bagId: Long): List<BagLotLineResponse> {
    val lines = bagLotLineRepository.findAllByBagId(bagId)
    return lines.map { line ->
        BagLotLineResponse(
            id = line.id ?: 0L,
            bagId = line.bagId ?: 0L,
            lotNo = line.lotNo,
            stockOutLineId = line.stockOutLineId,
            startQty = line.startQty,
            consumedQty = line.consumedQty,
            scrapQty = line.scrapQty,
            balanceQty = line.balanceQty,
            firstUseDate = line.firstUseDate,
            lastUseDate = line.lastUseDate
        )
    }
}


open fun getBagConsumptions(bagLotLineId: Long): List<BagConsumptionResponse> {
    val records = joBagConsumptionRepository.findAllByBagLotLineIdAndDeletedIsFalse(bagLotLineId)
    return records.map { r ->
        BagConsumptionResponse(
            id = r.id ?: 0L,
            bagId = r.bagId ?: 0L,
            bagLotLineId = r.bagLotLineId ?: 0L,
            jobId = r.jobId ?: 0L,
            jobOrderCode = r.jobOrderCode,
            stockOutLineId = r.stockOutLineId,
            startQty = r.startQty,
            consumedQty = r.consumedQty,
            scrapQty = r.scrapQty,
            endQty = r.endQty,
            date = r.date,
            time = r.time
        )
    }
}

open fun softDeleteBagByItemId(itemId: Long): MessageResponse {
    val bag = bagRepository.findByItemIdAndDeletedIsFalse(itemId)
    if (bag == null) {
        return MessageResponse(
            id = null,
            code = null,
            name = null,
            type = null,
            message = "No bag found for itemId: $itemId",
            errorPosition = null,
            entity = null,
        )
    }
    
    bag.deleted = true
    bagRepository.save(bag)
    
    return MessageResponse(
        id = bag.id,
        code = null,
        name = null,
        type = null,
        message = "Bag soft-deleted successfully",
        errorPosition = null,
        entity = null,
    )
}
}