package com.ffii.fpsms.modules.deliveryOrder.service

import com.ffii.fpsms.m18.entity.M18DataLogRepository
import com.ffii.fpsms.m18.service.M18DataLogService
import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrder
import com.ffii.fpsms.modules.deliveryOrder.entity.DeliveryOrderRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.models.DeliveryOrderInfo
import com.ffii.fpsms.modules.deliveryOrder.enums.DeliveryOrderStatus
import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderRequest
import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderResponse
import com.ffii.fpsms.modules.deliveryOrder.web.models.SaveDeliveryOrderStatusRequest
import com.ffii.fpsms.modules.master.service.CurrencyService
import com.ffii.fpsms.modules.master.service.ShopService
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.purchaseOrder.enums.PurchaseOrderStatus
import com.ffii.fpsms.modules.user.entity.UserRepository
import com.ffii.fpsms.modules.user.service.UserService
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.io.IOException
import kotlin.jvm.optionals.getOrDefault
import kotlin.jvm.optionals.getOrNull

@Service
open class DeliveryOrderService(
    private val deliveryOrderRepository: DeliveryOrderRepository,
    private val shopService: ShopService,
    private val currencyService: CurrencyService,
    private val m18DataLogService: M18DataLogService,
    private val m18DataLogRepository: M18DataLogRepository,
    private val userService: UserService,
    private val userRepository: UserRepository,
) {

    open fun findByM18DataLogId(m18DataLogId: Long): DeliveryOrder? {
        return deliveryOrderRepository.findTopByM18DataLogIdAndDeletedIsFalseOrderByModifiedDesc(m18DataLogId)
    }

    open fun getDoList() : List<DeliveryOrderInfo> {
        return deliveryOrderRepository.findDeliveryOrderInfoByDeletedIsFalse();
    }

    open fun getDetailedDo(id: Long) : DeliveryOrder? {
        return deliveryOrderRepository.findByIdAndDeletedIsFalse(id);
    }

    open fun updateDeliveryOrderStatus(request: SaveDeliveryOrderStatusRequest): SaveDeliveryOrderResponse {
        val deliveryOrder = checkNotNull(
            request.id?.let { deliveryOrderRepository.findById(it).getOrNull() }
        ) { "ID must be set" }

        val status = checkNotNull(
            request.status?.let { status -> DeliveryOrderStatus.entries.find { it.value == status } }
        ) { "Status must be set" }

        deliveryOrder.apply {
            this.status = status
        }

        val savedDeliveryOrder = deliveryOrderRepository.save(deliveryOrder).let {
            SaveDeliveryOrderResponse(
                id = it.id,
                code = it.code,
                supplierCode = it.supplier?.code,
                shopCode = it.shop?.code,
                currencyCode = it.currency?.code,
                orderDate = it.orderDate,
                estimatedArrivalDate = it.estimatedArrivalDate,
                completeDate = it.completeDate,
                status = it.status?.value
            )
        }

        return savedDeliveryOrder
    }

    @Throws(IOException::class)
    @Transactional
    open fun saveDeliveryOrder(request: SaveDeliveryOrderRequest): SaveDeliveryOrderResponse {
        val deliveryOrder =
            request.id?.let { deliveryOrderRepository.findById(it).getOrDefault(DeliveryOrder()) } ?: DeliveryOrder()
        val supplier = request.m18SupplierId?.let { shopService.findVendorByM18Id(it) }
            ?: request.supplierId?.let { shopService.findById(it) }
        val shop = request.m18ShopId?.let { shopService.findShopByM18Id(it) }
            ?: request.shopId?.let { shopService.findById(it) }
        val currency = request.m18CurrencyId?.let { currencyService.findByM18Id(it) }
            ?: request.currencyId?.let { currencyService.findById(it) }
        val status = request.status?.let { status -> DeliveryOrderStatus.entries.find { it.value == status } }
        val m18DataLog = request.m18DataLogId?.let { m18DataLogRepository.findById(it).getOrNull() }
        val handler = request.handlerId?.let { userRepository.findById(it).getOrNull() }

        //Need check duplicate?
        deliveryOrder.apply {
            code = request.code
            this.supplier = supplier
            this.shop = shop
            this.currency = currency
            orderDate = request.orderDate
            estimatedArrivalDate = request.estimatedArrivalDate
            completeDate = request.completeDate
            this.status = status
            this.m18DataLog = m18DataLog
            this.handler = handler
        }

        val savedDeliveryOrder = deliveryOrderRepository.saveAndFlush(deliveryOrder).let {
            SaveDeliveryOrderResponse(
                id = it.id,
                code = it.code,
                supplierCode = it.supplier?.code,
                shopCode = it.shop?.code,
                currencyCode = it.currency?.code,
                orderDate = it.orderDate,
                estimatedArrivalDate = it.estimatedArrivalDate,
                completeDate = it.completeDate,
                status = it.status?.value
            )
        }

        return savedDeliveryOrder
    }
}