package com.ffii.fpsms.modules.master.web

import com.ffii.core.response.RecordsRes
import com.ffii.core.utils.CriteriaArgsBuilder
import com.ffii.fpsms.modules.master.entity.ProductionScheduleRepository
import com.ffii.fpsms.modules.master.entity.projections.DetailedProdScheduleWithLine
import com.ffii.fpsms.modules.master.entity.projections.ProdScheduleInfo
import com.ffii.fpsms.modules.master.entity.projections.RoughProdScheduleWithLine
import com.ffii.fpsms.modules.master.service.ProductionScheduleService
import com.ffii.fpsms.modules.master.service.ProductionScheduleService.FinishedGood
import com.ffii.fpsms.modules.master.service.ProductionScheduleService.RoughScheduleObj
import com.ffii.fpsms.modules.master.web.models.MessageResponse
import com.ffii.fpsms.modules.master.web.models.ReleaseProdScheduleLineRequest
import com.ffii.fpsms.modules.master.web.models.SearchProdScheduleRequest
import jakarta.servlet.http.HttpServletRequest
import jakarta.validation.Valid
import org.springframework.web.bind.annotation.*
import java.time.Duration
import java.time.LocalDateTime
import java.util.HashMap
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.math.abs


@RestController
@RequestMapping("/productionSchedule")
class ProductionScheduleController(
    private val productionScheduleService: ProductionScheduleService,
    private val productionScheduleRepository: ProductionScheduleRepository,
) {
//    @GetMapping
//    fun allItems(): List<Items> {
//        return uomConversionService.allItems()
//    }

    @GetMapping("/test")
    fun test(request: HttpServletRequest): Any {
        val criteriaArgs = CriteriaArgsBuilder.withRequest(request)
            .addStringLike("type")
            .build()
        if (!criteriaArgs.containsKey("type")) {
            criteriaArgs["type"] = "rough"
        }
        return productionScheduleService.getLatestScheduleAt("rough")
    }

    @GetMapping("/detail/rough/{id}")
    fun getScheduleDetail(@PathVariable id: Long): RoughProdScheduleWithLine {
        return productionScheduleService.roughProdScheduleDetail(id)
    }

    @GetMapping("/detail/detailed/{id}")
    fun getDetailedProdScheduleDetail(@PathVariable id: Long): DetailedProdScheduleWithLine {
        return productionScheduleService.detailedProdScheduleDetail(id)
    }

    @PostMapping("/detail/detailed/save")
    fun saveDetailedProdScheduleDetail(@Valid @RequestBody request: ReleaseProdScheduleLineRequest): MessageResponse {
        return productionScheduleService.saveProdScheduleLine(request)
    }

    @PostMapping("/detail/detailed/releaseLine")
    fun releaseProdScheduleLine(@Valid @RequestBody request: ReleaseProdScheduleLineRequest): MessageResponse {
        return productionScheduleService.releaseProdScheduleLine(request)
    }

    @GetMapping("/getRecordByPage")
    fun allProdSchedulesByPage(@ModelAttribute request: SearchProdScheduleRequest): RecordsRes<ProdScheduleInfo> {
        return productionScheduleService.allProdSchedulesByPage(request);
    }



    @RequestMapping(value = ["/testDetailSchedule"], method = [RequestMethod.GET])
    fun generateDetailSchedule(request: HttpServletRequest?): Int {
        try {
            // For test
            val genDate = request?.getParameter("genDate").let { LocalDateTime.parse(it) }

            val today = LocalDateTime.now()
            val latestRoughScheduleAt = productionScheduleService.getLatestScheduleAt("rough")
            val assignDate = abs(Duration.between(latestRoughScheduleAt, today).toDays() % 7) + 1
//            val finalAssignDate = if (assignDate.toInt() == 0) {
//                1
//            } else assignDate.toInt()
            //TODO: update this to receive selectedDate and assignDate from schedule
//            productionScheduleService.generateDetailedScheduleByDay(1, LocalDateTime.of(2025,6,25,0,0,0))
            println("today： $today | latestRoughScheduleAty: $latestRoughScheduleAt | assignDate: $assignDate ")
            productionScheduleService.generateDetailedScheduleByDay(assignDate.toInt(), genDate ?: LocalDateTime.now())
            return 200
        } catch (e: Exception) {
            throw RuntimeException("Error generate schedule: ${e.message}", e)
        }
    }

    @RequestMapping(value = ["/testRoughSchedule"], method = [RequestMethod.GET])
    fun generateRoughSchedule(request: HttpServletRequest?): List<HashMap<RoughScheduleObj, Double>> {
        try {
            val demoFGList_old = arrayListOf<FinishedGood>(
                FinishedGood(
                1,
                "豆腐花 - Tofu pudding",
                3,
                91.0,
                31.0,
                3000.0
                ),
                FinishedGood(
                    2,
                    "中湯包 - Chinese Soup",
                    4,
                    100.0,
                    72.5,
                    3000.0
                ),
                FinishedGood(
                    3,
                    "苦瓜炒蛋 - Fried Egg",
                    3,
                    700.0,
                    300.5,
                    22000.0
                ),
                FinishedGood(
                    4,
                    "酸菜魚湯包 - Pickled fish soup",
                    4,
                    3000.0,
                    600.5,
                    22000.0
                ),
                FinishedGood(
                    5,
                    "咖哩雞球 - Curry chicken balls",
                    5,
                    3000.0,
                    2150.5,
                    22000.0
                ),
                FinishedGood(
                    6,
                    "水煮牛 - Spicy Beef",
                    6,
                    1000.0,
                    2000.5,
                    22000.0
                ),
                FinishedGood(
                    6,
                    "海鮮濃湯 - Sea Food Soup",
                    6,
                    0.0,
                    3500.5,
                    22000.0
                ),
                FinishedGood(
                    7,
                    "薯條 - Fries",
                    7,
                    0.0,
                    3000.5,
                    22000.0
                ),
            );

            val demoFGList = productionScheduleService.convertToFinishedGoodList();

            val result: HashMap<RoughScheduleObj, Double> = productionScheduleService.generateRoughScheduleByWeek(demoFGList)
            val sortedEntries = result.entries.sortedBy { it.value }


            var accProdCount = 0.0;
            var fgCount = 0L;
            for ((roughScheduleRecord, totalDifference) in sortedEntries) {
                accProdCount += roughScheduleRecord.totalProductionCount;
                fgCount ++;
                println("[totalDifference:" + totalDifference + "] - " + roughScheduleRecord.toString())
            }

            // Convert to List<HashMap<RoughScheduleObj, Double>>
            productionScheduleService.saveRoughScheduleOutput(sortedEntries, accProdCount, fgCount);
            return sortedEntries.map { entry ->
                hashMapOf(entry.key to entry.value)
            }
        } catch (e: Exception) {
            throw RuntimeException("Error generate schedule: ${e.message}", e)
        }
    }
}