package com.ffii.fpsms.m18.service

import com.ffii.core.utils.JwtTokenUtil
import com.ffii.fpsms.m18.web.models.M18CommonRequest
import com.ffii.fpsms.modules.common.SettingNames
import com.ffii.fpsms.modules.settings.service.SettingsService
import jakarta.annotation.PostConstruct
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.scheduling.TaskScheduler
//import org.springframework.scheduling.annotation.Async
import org.springframework.scheduling.annotation.Scheduled
import org.springframework.scheduling.support.CronTrigger
import org.springframework.stereotype.Service
import java.time.LocalDateTime
import java.time.format.DateTimeFormatter
import java.util.concurrent.ScheduledFuture
import kotlin.concurrent.Volatile
import kotlin.jvm.optionals.getOrNull

@Service
open class M18SchedulerService(
    val m18PurchaseOrderService: M18PurchaseOrderService,
    val m18DeliveryOrderService: M18DeliveryOrderService,
    val m18MasterDataService: M18MasterDataService,
    val settingsService: SettingsService,
    val taskScheduler: TaskScheduler,
) {
    var logger: Logger = LoggerFactory.getLogger(JwtTokenUtil::class.java)
    val dataStringFormat = DateTimeFormatter.ofPattern("yyyy-MM-dd")
    val defaultCronExpression = "0 0 2 * * *";

    @Volatile
    var scheduledM18Po: ScheduledFuture<*>? = null

    @Volatile
    var scheduledM18Master: ScheduledFuture<*>? = null

    fun isValidCronExpression(cronExpression: String): Boolean {
        return try {
            CronTrigger(cronExpression)
            true
        } catch (e: IllegalArgumentException) {
            false
        }
    }
    @PostConstruct
    fun init() {
        scheduleM18PoTask()
        scheduleM18MasterData()
    }

    fun commonSchedule(scheduled: ScheduledFuture<*>?, settingName: String, scheduleFunc: () -> Unit) {
        scheduled?.cancel(false)

        var cron = settingsService.findByName(settingName).getOrNull()?.value ?: defaultCronExpression;

        if (!isValidCronExpression(cron)) {
            cron = defaultCronExpression
        }
        scheduledM18Po = taskScheduler.schedule(
            {
                scheduleFunc()
            },
            CronTrigger(cron)
        )
    }

    // Scheduler
    fun scheduleM18PoTask() {
        commonSchedule(scheduledM18Po, SettingNames.SCHEDULE_M18_PO, ::getM18Pos)
    }

    fun scheduleM18MasterData() {
        commonSchedule(scheduledM18Master, SettingNames.SCHEDULE_M18_MASTER, ::getM18MasterData)
    }

    // Tasks
//    @Async
//    @Scheduled(cron = "0 0 2 * * *") // (SS/MM/HH/DD/MM/YY)
    open fun getM18Pos() {
        logger.info("Daily Scheduler - PO")
        val currentTime = LocalDateTime.now()
        val today = currentTime.toLocalDate().atStartOfDay()
        val yesterday = today.minusDays(1L)
        val request = M18CommonRequest(
            modifiedDateTo = today.format(dataStringFormat),
            modifiedDateFrom = yesterday.format(dataStringFormat)
        )
        m18PurchaseOrderService.savePurchaseOrders(request);
        m18DeliveryOrderService.saveDeliveryOrders(request);
        logger.info("today: ${today.format(dataStringFormat)}")
        logger.info("yesterday: ${yesterday.format(dataStringFormat)}")
    }

    open fun getM18MasterData() {
        logger.info("Daily Scheduler - Master Data")
        val currentTime = LocalDateTime.now()
        val today = currentTime.toLocalDate().atStartOfDay()
        val yesterday = today.minusDays(1L)
        val request = M18CommonRequest(
            modifiedDateTo = today.format(dataStringFormat),
            modifiedDateFrom = yesterday.format(dataStringFormat)
        )
        m18MasterDataService.saveUnits(request)
        m18MasterDataService.saveProducts(request)
        m18MasterDataService.saveVendors(request)
        m18MasterDataService.saveBusinessUnits(request)
        m18MasterDataService.saveCurrencies(request)
        logger.info("today: ${today.format(dataStringFormat)}")
        logger.info("yesterday: ${yesterday.format(dataStringFormat)}")
    }
}