package com.ffii.fpsms.modules.pickOrder.service

import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderLineRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRecordRepository
import com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrderRepository
import com.ffii.fpsms.modules.deliveryOrder.enums.DoPickOrderStatus
import com.ffii.fpsms.modules.jobOrder.entity.JoPickOrderRecordRepository
import com.ffii.fpsms.modules.jobOrder.entity.JoPickOrderRepository
import com.ffii.fpsms.modules.jobOrder.enums.JoPickOrderStatus
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderGroupRepository
import com.ffii.fpsms.modules.pickOrder.entity.PickOrderRepository
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderStatus
import com.ffii.fpsms.modules.pickOrder.enums.PickOrderType
import com.ffii.fpsms.modules.pickOrder.web.models.*
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import java.time.format.DateTimeFormatter

@Service
@Transactional(readOnly = true)
open class PickOrderLifecycleService(
    private val pickOrderRepository: PickOrderRepository,
    private val pickOrderGroupRepository: PickOrderGroupRepository,
    private val doPickOrderRepository: DoPickOrderRepository,
    private val doPickOrderRecordRepository: DoPickOrderRecordRepository,
    private val doPickOrderLineRepository: DoPickOrderLineRepository,
    private val joPickOrderRepository: JoPickOrderRepository,
    private val joPickOrderRecordRepository: JoPickOrderRecordRepository,
) {
    private val dtf = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")

    /** FP-MTMS Version Checklist | Functions Ref. No. 11 | v1.0.0 | 2026-07-17 */
    open fun getLifecycle(pickOrderId: Long): PickOrderLifecycleResponse? {
        val po = pickOrderRepository.findById(pickOrderId).orElse(null) ?: return null

        val groups = po.id?.let { pickOrderGroupRepository.findByPickOrderIdAndDeletedIsFalse(it) } ?: emptyList()
        val groupName = groups.firstOrNull()?.name

        val stages = buildPickOrderStages(po)
        val doLifecycle = if (po.type == PickOrderType.DELIVERY_ORDER) buildDoLifecycle(pickOrderId) else null
        val joLifecycle = if (po.type == PickOrderType.JOB_ORDER) buildJoLifecycle(pickOrderId) else null

        return PickOrderLifecycleResponse(
            pickOrderId = po.id!!,
            pickOrderCode = po.code ?: "",
            pickOrderType = po.type?.value ?: "",
            currentStatus = po.status?.value ?: "",
            targetDate = po.targetDate?.format(dtf),
            completeDate = po.completeDate?.format(dtf),
            consoCode = po.consoCode,
            groupName = groupName,
            totalLines = po.totalLines,
            submittedLines = po.submittedLines,
            stages = stages,
            doLifecycle = doLifecycle,
            joLifecycle = joLifecycle,
        )
    }

    /** FP-MTMS Version Checklist | Functions Ref. No. 11 | v1.0.0 | 2026-07-17 */
    open fun getLifecycleByCode(code: String): PickOrderLifecycleResponse? {
        val po = pickOrderRepository.findByCodeAndDeletedFalse(code) ?: return null
        return po.id?.let { getLifecycle(it) }
    }

    private fun buildPickOrderStages(po: com.ffii.fpsms.modules.pickOrder.entity.PickOrder): List<LifecycleStage> {
        val currentStatus = po.status ?: PickOrderStatus.PENDING
        val statusOrder = listOf(
            PickOrderStatus.PENDING to "待處理",
            PickOrderStatus.CONSOLIDATED to "已合併",
            PickOrderStatus.ASSIGNED to "已指派",
            PickOrderStatus.RELEASED to "已發放",
            PickOrderStatus.PICKING to "提料中",
            PickOrderStatus.COMPLETED to "已完成",
        )

        val currentIdx = statusOrder.indexOfFirst { it.first == currentStatus }

        return statusOrder.mapIndexed { idx, (status, label) ->
            val reached = idx <= currentIdx
            val isCurrent = status == currentStatus
            LifecycleStage(
                status = status.value,
                label = label,
                reached = reached,
                timestamp = when (status) {
                    PickOrderStatus.RELEASED -> po.releasedDate?.format(dtf)
                    PickOrderStatus.COMPLETED -> po.completeDate?.format(dtf)
                    else -> null
                },
                actor = when (status) {
                    PickOrderStatus.RELEASED -> po.releasedBy?.name
                    PickOrderStatus.ASSIGNED -> po.assignTo?.name
                    else -> null
                },
                actorId = when (status) {
                    PickOrderStatus.RELEASED -> po.releasedBy?.id
                    PickOrderStatus.ASSIGNED -> po.assignTo?.id
                    else -> null
                },
                isCurrent = isCurrent,
                details = buildStageDetails(po, status),
            )
        }
    }

    private fun buildStageDetails(
        po: com.ffii.fpsms.modules.pickOrder.entity.PickOrder,
        status: PickOrderStatus
    ): Map<String, String?> {
        val map = mutableMapOf<String, String?>()
        when (status) {
            PickOrderStatus.CONSOLIDATED -> {
                po.consoCode?.let { map["consoCode"] = it }
            }
            PickOrderStatus.RELEASED -> {
                po.consoCode?.let { map["consoCode"] = it }
                map["plasticBoxCartonQty2f"] = po.plasticBoxCartonQty2f?.toString()
                map["plasticBoxCartonQty3f"] = po.plasticBoxCartonQty3f?.toString()
                map["plasticBoxCartonQty4f"] = po.plasticBoxCartonQty4f?.toString()
            }
            PickOrderStatus.COMPLETED -> {
                map["totalLines"] = po.totalLines?.toString()
                map["submittedLines"] = po.submittedLines?.toString()
            }
            else -> {}
        }
        return map
    }

    private fun buildDoLifecycle(pickOrderId: Long): DoLifecycleInfo? {
        // Check active do_pick_order first
        val doPickOrderLines = doPickOrderLineRepository.findByPickOrderIdAndDeletedFalse(pickOrderId)
        val doPickOrderId = doPickOrderLines.firstOrNull()?.doPickOrderId

        var dpo = doPickOrderId?.let { doPickOrderRepository.findById(it).orElse(null) }
        var deliveryNoteCode: String? = null

        // If not in active table, check record table
        if (dpo == null) {
            val records = doPickOrderRecordRepository.findByPickOrderId(pickOrderId)
            val record = records.maxByOrNull { it.id ?: 0L }
            if (record != null) {
                deliveryNoteCode = record.deliveryNoteCode
            }
        }

        if (dpo == null && deliveryNoteCode == null) {
            // Try do_pick_order_record by looking up via delivery_order
            val po = pickOrderRepository.findById(pickOrderId).orElse(null)
            val doId = po?.deliveryOrder?.id
            if (doId != null) {
                val doRecords = doPickOrderRecordRepository.findByDoOrderIdAndDeletedFalse(doId)
                val doRecord = doRecords.firstOrNull()
                if (doRecord != null) {
                    deliveryNoteCode = doRecord.deliveryNoteCode
                }
            }
        }

        if (dpo == null && deliveryNoteCode == null) return null

        val stages = buildDoStages(dpo)
        return DoLifecycleInfo(
            doPickOrderId = dpo?.id,
            ticketNo = dpo?.ticketNo,
            ticketStatus = dpo?.ticketStatus?.value ?: DoPickOrderStatus.completed.value,
            storeId = dpo?.storeId,
            shopName = dpo?.shopName,
            truckLanceCode = dpo?.truckLanceCode,
            deliveryNoteCode = deliveryNoteCode,
            deliveryOrderCode = dpo?.deliveryOrderCode,
            loadingSequence = dpo?.loadingSequence,
            stages = stages,
        )
    }

    private fun buildDoStages(dpo: com.ffii.fpsms.modules.deliveryOrder.entity.DoPickOrder?): List<LifecycleStage> {
        val currentStatus = dpo?.ticketStatus ?: DoPickOrderStatus.completed
        val statusOrder = listOf(
            DoPickOrderStatus.pending to "DO待處理",
            DoPickOrderStatus.released to "DO已發放",
            DoPickOrderStatus.completed to "DO已完成(DN產生)",
        )

        val currentIdx = statusOrder.indexOfFirst { it.first == currentStatus }
        if (currentIdx < 0 && dpo == null) {
            // Already completed and archived
            return statusOrder.mapIndexed { idx, (status, label) ->
                LifecycleStage(
                    status = status.value,
                    label = label,
                    reached = true,
                    timestamp = null,
                    actor = null,
                    actorId = null,
                    isCurrent = false,
                )
            }
        }

        return statusOrder.mapIndexed { idx, (status, label) ->
            val reached = idx <= maxOf(currentIdx, 0)
            val isCurrent = status == currentStatus
            LifecycleStage(
                status = status.value,
                label = label,
                reached = reached,
                timestamp = when (status) {
                    DoPickOrderStatus.released -> dpo?.ticketReleaseTime?.format(dtf)
                    DoPickOrderStatus.completed -> dpo?.ticketCompleteDateTime?.format(dtf)
                    else -> null
                },
                actor = when (status) {
                    DoPickOrderStatus.released -> dpo?.handlerName
                    DoPickOrderStatus.completed -> dpo?.handlerName
                    else -> null
                },
                actorId = dpo?.handledBy,
                isCurrent = isCurrent,
            )
        }
    }

    private fun buildJoLifecycle(pickOrderId: Long): JoLifecycleInfo? {
        val jpos = joPickOrderRepository.findByPickOrderId(pickOrderId)
        val jpo = jpos.firstOrNull()

        // Check record table if not in active
        val jpoRecord = if (jpo == null) {
            joPickOrderRecordRepository.findByPickOrderId(pickOrderId).firstOrNull()
        } else null

        if (jpo == null && jpoRecord == null) return null

        val stages = buildJoStages(jpo)
        return JoLifecycleInfo(
            joPickOrderId = jpo?.id ?: jpoRecord?.id,
            jobOrderCode = jpo?.jobOrderCode ?: jpoRecord?.jobOrderCode,
            matchStatus = jpo?.matchStatus?.value ?: jpoRecord?.matchStatus?.value,
            matchQty = jpo?.matchQty ?: jpoRecord?.matchQty,
            matchBy = jpo?.matchingBy?.toString() ?: jpoRecord?.matchBy?.toString(),
            stages = stages,
        )
    }

    private fun buildJoStages(jpo: com.ffii.fpsms.modules.jobOrder.entity.JoPickOrder?): List<LifecycleStage> {
        val currentStatus = jpo?.matchStatus ?: JoPickOrderStatus.completed
        val statusOrder = listOf(
            JoPickOrderStatus.pending to "等待二次掃描",
            JoPickOrderStatus.scanned to "已掃描",
            JoPickOrderStatus.completed to "配對完成",
        )

        val currentIdx = statusOrder.indexOfFirst { it.first == currentStatus }
        if (currentIdx < 0 && jpo == null) {
            return statusOrder.mapIndexed { idx, (status, label) ->
                LifecycleStage(
                    status = status.value,
                    label = label,
                    reached = true,
                    timestamp = null,
                    actor = null,
                    actorId = null,
                    isCurrent = false,
                )
            }
        }

        return statusOrder.mapIndexed { idx, (status, label) ->
            val reached = idx <= maxOf(currentIdx, 0)
            val isCurrent = status == currentStatus
            LifecycleStage(
                status = status.value,
                label = label,
                reached = reached,
                timestamp = null,
                actor = null,
                actorId = jpo?.matchingBy,
                isCurrent = isCurrent,
            )
        }
    }
}
