package com.ffii.fpsms.py

import com.ffii.fpsms.modules.jobOrder.entity.JobOrderRepository
import com.ffii.fpsms.modules.jobOrder.service.PlasticBagPrinterService
import com.ffii.fpsms.modules.master.service.ItemUomService
import com.ffii.fpsms.modules.stock.entity.StockInLineRepository
import org.springframework.format.annotation.DateTimeFormat
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import org.springframework.web.server.ResponseStatusException
import org.springframework.http.HttpStatus
import java.time.LocalDate

/**
 * Public API for Python clients. No login required.
 * Base path: /py
 */
@RestController
@RequestMapping("/py")
open class PyController(
    private val jobOrderRepository: JobOrderRepository,
    private val stockInLineRepository: StockInLineRepository,
    private val itemUomService: ItemUomService,
    private val plasticBagPrinterService: PlasticBagPrinterService,
    private val pyJobOrderPrintSubmitService: PyJobOrderPrintSubmitService,
) {
    companion object {
        private const val PACKAGING_PROCESS_NAME = "包裝"
    }

    /**
     * List job orders by planStart date.
     * GET /py/job-orders?planStart=yyyy-MM-dd
     * @param planStart Date to filter by (default: today). Format: yyyy-MM-dd
     * @return List of job orders with id, code, planStart, itemCode, itemName, reqQty, stockInLineId, itemId
     */
    @GetMapping("/job-orders")
    open fun listJobOrders(
        @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) planStart: LocalDate?,
    ): ResponseEntity<List<PyJobOrderListItem>> {
        val date = planStart ?: LocalDate.now()
        val dayStart = date.atStartOfDay()
        val dayEndExclusive = date.plusDays(1).atStartOfDay()
        val orders = jobOrderRepository.findByDeletedFalseAndPlanStartBetweenAndBomProcessNameOrderByIdAsc(
            dayStart,
            dayEndExclusive,
            PACKAGING_PROCESS_NAME,
        )
        val ids = orders.mapNotNull { it.id }
        val printed = pyJobOrderPrintSubmitService.sumPrintedQtyByJobOrderIds(ids)
        val list = orders.map { jo ->
            PyJobOrderListMapper.toListItem(jo, printed[jo.id!!], stockInLineRepository, itemUomService)
        }
        return ResponseEntity.ok(list)
    }

    /**
     * Record a print submit from Bag2 (e.g. 標簽機). No login.
     * POST /py/job-order-print-submit
     * Body: { "jobOrderId": 1, "qty": 10, "printChannel": "LABEL" | "DATAFLEX" | "LASER" }
     */
    @PostMapping("/job-order-print-submit")
    open fun submitJobOrderPrint(
        @RequestBody body: PyJobOrderPrintSubmitRequest,
    ): ResponseEntity<PyJobOrderPrintSubmitResponse> {
        val channel = body.printChannel?.trim()?.takeIf { it.isNotEmpty() } ?: PyPrintChannel.LABEL
        if (
            channel != PyPrintChannel.LABEL &&
            channel != PyPrintChannel.DATAFLEX &&
            channel != PyPrintChannel.LASER
        ) {
            throw ResponseStatusException(HttpStatus.BAD_REQUEST, "Unsupported printChannel: $channel")
        }
        return ResponseEntity.ok(pyJobOrderPrintSubmitService.recordPrint(body.jobOrderId, body.qty, channel))
    }

    /**
     * Same as [listJobOrders] but filtered by system setting [com.ffii.fpsms.modules.common.SettingNames.LASER_PRINT_ITEM_CODES]
     * (comma-separated item codes). Public — no login (same as /py/job-orders).
     */
    @GetMapping("/laser-job-orders")
    open fun listLaserJobOrders(
        @RequestParam(required = false) @DateTimeFormat(iso = DateTimeFormat.ISO.DATE) planStart: LocalDate?,
    ): ResponseEntity<List<PyJobOrderListItem>> {
        val date = planStart ?: LocalDate.now()
        return ResponseEntity.ok(plasticBagPrinterService.listLaserPrintJobOrders(date))
    }
}
