import { prisma } from "@/core/prisma"
import { AppError } from "@/core/AppError"
import { tracked } from "@/core/tracked"
import { LifecycleEventType, OrderItemStatus, Prisma } from "@prisma/client"
import {
    buildDefaultProductionWorkflowDto,
    buildProductionWorkflowSnapshot,
    getAcknowledgedProductionStepState,
    toProductionWorkflowDto,
} from "./production-workflow"

type StockVariantType = "STANDARD" | "CUSTOMIZED"

type VariantCustomizationLike = {
    action: "ADDED" | "REMOVED"
    ingredientId: string | null
    ingredientName: string
    quantity: number
}

type VariantConfigurationPathNodeLike = {
    groupId?: string | null
    groupCode?: string | null
    groupLabel?: string | null
    choiceId?: string | null
    choiceCode?: string | null
    choiceLabel?: string | null
    priceDelta?: number | null
}

type VariantConfigurationEntryLike = {
    index?: number | null
    label?: string | null
    unitPriceDelta?: number | null
    path?: VariantConfigurationPathNodeLike[] | null
}

type VariantConfigurationStepLike = {
    stepId?: string | null
    stepCode?: string | null
    stepLabel?: string | null
    repeatCount?: number | null
    entries?: VariantConfigurationEntryLike[] | null
}

type VariantConfigurationSnapshotLike = {
    configuratorId?: string | null
    configuratorName?: string | null
    version?: number | null
    totalUnitPriceDelta?: number | null
    steps?: VariantConfigurationStepLike[] | null
}

type VariantOrderItemLike = {
    quantity?: number | null
    recipeId: string | null
    configurationSnapshot?: VariantConfigurationSnapshotLike | null
    productionOverrideSnapshot?: VariantConfigurationSnapshotLike | null
    customizations?: VariantCustomizationLike[]
}

type ResolvedStockUnit = {
    variantType: StockVariantType
    variantKey: string
    variantLabel: string | null
    quantity: number
}

export type OrderItemStockCoverageSummary = {
    totalUnits: number
    coveredUnits: number
    remainingUnits: number
}

type PartialConfiguratorCoverage = {
    totalUnits: number
    coveredUnits: number
    remainingUnits: number
    coverageByVariantKey: Map<string, number>
    remainingSnapshot: VariantConfigurationSnapshotLike
}

function normalizeStockText(value: string | null | undefined) {
    return value?.trim() ?? ""
}

function encodeStockKeyPart(value: string) {
    return encodeURIComponent(value)
}

function decodeStockKeyPart(value: string) {
    try {
        return decodeURIComponent(value)
    } catch {
        return value
    }
}

function readConfigurationSnapshot(value: unknown): VariantConfigurationSnapshotLike | null {
    if (!value || typeof value !== "object" || Array.isArray(value)) {
        return null
    }

    return value as VariantConfigurationSnapshotLike
}

function buildCustomizationSignature(customizations?: VariantCustomizationLike[]) {
    return (customizations ?? [])
        .map((customization) => {
            const ingredientKey = customization.ingredientId
                ?? customization.ingredientName.trim().toLowerCase()
            return [customization.action, ingredientKey, customization.quantity ?? 1].join(":")
        })
        .sort()
        .join("|")
}

function buildConfigurationPathSignature(entry: VariantConfigurationEntryLike) {
    return (entry.path ?? [])
        .map((node) => `${normalizeStockText(node.groupCode).toLowerCase()}=${normalizeStockText(node.choiceCode).toLowerCase()}`)
        .filter((part) => part !== "=")
        .join(">")
}

function buildConfigurationEntryLabel(step: VariantConfigurationStepLike, entry: VariantConfigurationEntryLike) {
    const pathLabel = (entry.path ?? [])
        .map((node) => normalizeStockText(node.choiceLabel))
        .filter(Boolean)
        .join(" › ")

    const fallbackLabel = normalizeStockText(entry.label)
    const resolvedLabel = pathLabel || fallbackLabel || `Choix ${entry.index ?? "?"}`
    const stepLabel = normalizeStockText(step.stepLabel)

    if (!stepLabel) return resolvedLabel

    const loweredStep = stepLabel.toLocaleLowerCase("fr-FR")
    const loweredResolved = resolvedLabel.toLocaleLowerCase("fr-FR")
    const repeatedPrefix = `${loweredStep} › `
    if (loweredResolved.startsWith(repeatedPrefix)) {
        return resolvedLabel.slice(stepLabel.length + 3).trim()
    }

    return resolvedLabel
}

function buildConfiguratorVariantKey(
    configuratorId: string,
    step: VariantConfigurationStepLike,
    entry: VariantConfigurationEntryLike,
) {
    const stepCode = normalizeStockText(step.stepCode)
    const pathSignature = buildConfigurationPathSignature(entry)
    const variantLabel = buildConfigurationEntryLabel(step, entry)
    const fallbackSignature = normalizeStockText(entry.label).toLocaleLowerCase("fr-FR") || `index=${entry.index ?? "?"}`

    return {
        variantKey: [
            `cfg:${encodeStockKeyPart(configuratorId)}`,
            `step:${encodeStockKeyPart(stepCode)}`,
            `path:${encodeStockKeyPart(pathSignature || fallbackSignature)}`,
            `label:${encodeStockKeyPart(variantLabel)}`,
        ].join("|"),
        variantLabel,
    }
}

function buildConfiguratorStockUnits(snapshot: VariantConfigurationSnapshotLike | null | undefined, multiplier: number) {
    const configuratorId = normalizeStockText(snapshot?.configuratorId)
    const unitMultiplier = Math.max(1, multiplier)
    if (!configuratorId) return [] as ResolvedStockUnit[]

    const grouped = new Map<string, ResolvedStockUnit>()

    for (const step of snapshot?.steps ?? []) {
        const stepCode = normalizeStockText(step.stepCode)
        if (!stepCode) continue

        for (const entry of step.entries ?? []) {
            const { variantKey, variantLabel } = buildConfiguratorVariantKey(configuratorId, step, entry)

            const existing = grouped.get(variantKey)
            if (existing) {
                existing.quantity += unitMultiplier
            } else {
                grouped.set(variantKey, {
                    variantType: "CUSTOMIZED",
                    variantKey,
                    variantLabel,
                    quantity: unitMultiplier,
                })
            }
        }
    }

    return [...grouped.values()]
}

function sumResolvedStockUnitQuantity(units: ResolvedStockUnit[]) {
    return units.reduce((sum, unit) => sum + unit.quantity, 0)
}

function buildRemainingConfiguratorSnapshot(
    snapshot: VariantConfigurationSnapshotLike,
    consumedByVariantKey: Map<string, number>,
) {
    const configuratorId = normalizeStockText(snapshot.configuratorId)
    if (!configuratorId) return null

    const remainingConsumption = new Map(consumedByVariantKey)
    const nextSteps: VariantConfigurationStepLike[] = []
    let totalUnitPriceDelta = 0

    for (const step of snapshot.steps ?? []) {
        const nextEntries: VariantConfigurationEntryLike[] = []

        for (const entry of step.entries ?? []) {
            const { variantKey } = buildConfiguratorVariantKey(configuratorId, step, entry)
            const remainingToConsume = remainingConsumption.get(variantKey) ?? 0

            if (remainingToConsume > 0) {
                remainingConsumption.set(variantKey, remainingToConsume - 1)
                continue
            }

            totalUnitPriceDelta += entry.unitPriceDelta ?? 0
            nextEntries.push({
                index: entry.index ?? nextEntries.length,
                label: entry.label ?? null,
                unitPriceDelta: entry.unitPriceDelta ?? 0,
                path: (entry.path ?? []).map((node) => ({
                    groupId: node.groupId ?? null,
                    groupCode: node.groupCode ?? null,
                    groupLabel: node.groupLabel ?? null,
                    choiceId: node.choiceId ?? null,
                    choiceCode: node.choiceCode ?? null,
                    choiceLabel: node.choiceLabel ?? null,
                    priceDelta: node.priceDelta ?? 0,
                })),
            })
        }

        if (nextEntries.length === 0) continue

        nextSteps.push({
            stepId: step.stepId ?? null,
            stepCode: step.stepCode ?? null,
            stepLabel: step.stepLabel ?? null,
            repeatCount: step.repeatCount == null ? null : nextEntries.length,
            entries: nextEntries,
        })
    }

    if (nextSteps.length === 0) return null

    return {
        configuratorId,
        configuratorName: snapshot.configuratorName ?? null,
        version: snapshot.version ?? null,
        totalUnitPriceDelta,
        steps: nextSteps,
    }
}

function buildPartialConfiguratorCoverage(
    snapshot: VariantConfigurationSnapshotLike | null | undefined,
    existingStocks: Array<{ variantType: StockVariantType; variantKey: string; quantity: number }>,
): PartialConfiguratorCoverage | null {
    if (!snapshot) return null

    const requiredUnits = buildConfiguratorStockUnits(snapshot, 1)
    const totalUnits = sumResolvedStockUnitQuantity(requiredUnits)
    if (totalUnits <= 0) return null

    const coverageByVariantKey = new Map<string, number>()
    let coveredUnits = 0

    for (const requiredUnit of requiredUnits) {
        const existingStock = existingStocks.find((stock) =>
            stock.variantType === requiredUnit.variantType && stock.variantKey === requiredUnit.variantKey
        )
        const coveredQuantity = Math.min(existingStock?.quantity ?? 0, requiredUnit.quantity)
        if (coveredQuantity <= 0) continue

        coverageByVariantKey.set(requiredUnit.variantKey, coveredQuantity)
        coveredUnits += coveredQuantity
    }

    if (coveredUnits <= 0 || coveredUnits >= totalUnits) {
        return null
    }

    const remainingSnapshot = buildRemainingConfiguratorSnapshot(snapshot, coverageByVariantKey)
    if (!remainingSnapshot) return null

    return {
        totalUnits,
        coveredUnits,
        remainingUnits: totalUnits - coveredUnits,
        coverageByVariantKey,
        remainingSnapshot,
    }
}

function buildStockCoverageSummary(
    originalSnapshot: VariantConfigurationSnapshotLike | null | undefined,
    overrideSnapshot: VariantConfigurationSnapshotLike | null | undefined,
): OrderItemStockCoverageSummary | null {
    const totalUnits = sumResolvedStockUnitQuantity(buildConfiguratorStockUnits(originalSnapshot, 1))
    const remainingUnits = sumResolvedStockUnitQuantity(buildConfiguratorStockUnits(overrideSnapshot, 1))

    if (totalUnits <= 0 || remainingUnits <= 0 || remainingUnits >= totalUnits) {
        return null
    }

    return {
        totalUnits,
        coveredUnits: totalUnits - remainingUnits,
        remainingUnits,
    }
}

export function buildOrderItemProductionDisplayData(item: {
    status?: string | null
    configurationSnapshot?: unknown
    productionOverrideSnapshot?: unknown
}) {
    const originalSnapshot = readConfigurationSnapshot(item.configurationSnapshot)
    const overrideSnapshot = readConfigurationSnapshot(item.productionOverrideSnapshot)
    const shouldUseOverride =
        (item.status === OrderItemStatus.PENDING || item.status === OrderItemStatus.PREPARING)
        && Boolean(overrideSnapshot)

    return {
        productionConfigurationSnapshot: shouldUseOverride ? overrideSnapshot : null,
        stockCoverage: shouldUseOverride
            ? buildStockCoverageSummary(originalSnapshot, overrideSnapshot)
            : null,
    }
}

function resolveStockUnits(item: VariantOrderItemLike): ResolvedStockUnit[] {
    const multiplier = Math.max(1, item.quantity ?? 1)
    const configuratorUnits = buildConfiguratorStockUnits(item.configurationSnapshot, multiplier)
    if (configuratorUnits.length > 0) {
        return configuratorUnits
    }

    if ((item.customizations?.length ?? 0) === 0) {
        return [{ variantType: "STANDARD", variantKey: "STANDARD", variantLabel: null, quantity: multiplier }]
    }

    const recipeKey = item.recipeId ?? "base"
    const customizationSignature = buildCustomizationSignature(item.customizations)
    return [{
        variantType: "CUSTOMIZED",
        variantKey: `recipe:${recipeKey}|${customizationSignature}`,
        variantLabel: null,
        quantity: multiplier,
    }]
}

function readVariantLabel(variantType: StockVariantType, variantKey: string) {
    if (variantType !== "CUSTOMIZED") return null

    const encodedLabel = variantKey
        .split("|")
        .find((part) => part.startsWith("label:"))
        ?.slice("label:".length)

    if (!encodedLabel) return null
    const decoded = decodeStockKeyPart(encodedLabel)
    return decoded || null
}

export const stationStockService = {

    /**
     * Récupère le stock de réserve d'une station de production.
     */
    async getStock(shopId: string, stationId: string) {
        const stocks = await prisma.stationProductStock.findMany({
            where: { stationId, shopId, quantity: { gt: 0 } },
            include: {
                product: { select: { id: true, name: true, price: true } }
            },
            orderBy: { product: { name: "asc" } }
        })

        return stocks.map(s => ({
            id: s.id,
            stationId: s.stationId,
            productId: s.productId,
            productName: s.product.name,
            quantity: s.quantity,
            variantType: s.variantType,
            variantKey: s.variantKey,
            variantLabel: readVariantLabel(s.variantType, s.variantKey),
            updatedAt: s.updatedAt.toISOString()
        }))
    },

    /**
     * Envoie un item annulé en réserve.
     * L'item doit être CANCELLED et son previousStatus doit être PREPARING (ou READY).
     * Incrémente le stock de la station pour ce produit.
     */
    async sendToReserve(
        shopId: string,
        stationId: string,
        orderItemId: string,
        userId: string,
        senderSocketId?: string
    ) {
        const item = await prisma.orderItem.findFirst({
            where: {
                id: orderItemId,
                order: { shopId },
                status: "CANCELLED"
            },
            include: {
                customizations: true,
                product: true,
                order: true
            }
        })

        if (!item) {
            throw new AppError("Order item not found or not cancelled", 404)
        }

        const belongsToStation = item.currentStepStationId === stationId
            || (!item.logisticsRouteId && item.product.stationId === stationId)
            || item.product.stationId === stationId

        if (!belongsToStation) {
            throw new AppError("Item does not belong to this station", 400)
        }

        const stockUpdates = await prisma.$transaction(async (tx) => {
            const stockUnits = resolveStockUnits({
                ...item,
                configurationSnapshot: readConfigurationSnapshot(item.configurationSnapshot),
                productionOverrideSnapshot: readConfigurationSnapshot(item.productionOverrideSnapshot),
            })
            const updates: Array<{
                productId: string
                productName: string
                newQuantity: number
                variantType: StockVariantType
                variantKey: string
                variantLabel: string | null
                delta: number
            }> = []

            for (const stockUnit of stockUnits) {
                const stock = await tx.stationProductStock.upsert({
                    where: {
                        stationId_productId_variantType_variantKey: {
                            stationId,
                            productId: item.productId,
                            variantType: stockUnit.variantType,
                            variantKey: stockUnit.variantKey,
                        }
                    },
                    create: {
                        stationId,
                        productId: item.productId,
                        shopId,
                        quantity: stockUnit.quantity,
                        variantType: stockUnit.variantType,
                        variantKey: stockUnit.variantKey,
                    },
                    update: {
                        quantity: { increment: stockUnit.quantity }
                    }
                })

                updates.push({
                    productId: item.productId,
                    productName: item.product.name,
                    newQuantity: stock.quantity,
                    variantType: stockUnit.variantType,
                    variantKey: stockUnit.variantKey,
                    variantLabel: stockUnit.variantLabel,
                    delta: stockUnit.quantity,
                })
            }

            return updates
        })

        // Émettre l'événement
        const t = tracked({ shopId, entity: "Station", actorUserId: userId, senderSocketId })
        for (const stockUpdate of stockUpdates) {
            await t.emit(
                "station.stock_updated",
                {
                    stationId,
                    ...stockUpdate,
                    reason: "send_to_reserve",
                    orderItemId,
                },
                stationId,
                1
            )
        }

        const firstStockUpdate = stockUpdates[0] ?? null
        return {
            productId: firstStockUpdate?.productId ?? item.productId,
            productName: firstStockUpdate?.productName ?? item.product.name,
            newQuantity: firstStockUpdate?.newQuantity ?? 0,
            variantType: firstStockUpdate?.variantType ?? "STANDARD",
            variantKey: firstStockUpdate?.variantKey ?? "STANDARD",
            variantLabel: firstStockUpdate?.variantLabel ?? null,
            delta: firstStockUpdate?.delta ?? 0,
            stockUpdates,
        }
    },

    /**
     * Utilise du stock de réserve pour servir un item.
     * Passe l'item de PENDING à PREPARING et décrémente le stock.
     * Tout est dans une transaction pour éviter les race conditions.
     */
    async useFromStock(
        shopId: string,
        stationId: string,
        orderItemId: string,
        userId: string,
        senderSocketId?: string
    ) {
        const result = await prisma.$transaction(async (tx) => {
            const actor = await tx.shopUser.findUnique({
                where: { id: userId },
                select: { displayName: true, username: true, email: true },
            })
            const item = await tx.orderItem.findFirst({
                where: {
                    id: orderItemId,
                    order: { shopId },
                    status: "PENDING"
                },
                include: { product: true, customizations: true }
            })

            if (!item) {
                throw new AppError("Order item not found or not pending", 404)
            }

            const belongsToStation = item.currentStepStationId === stationId
                || (!item.logisticsRouteId && item.product.stationId === stationId)
                || item.product.stationId === stationId

            if (!belongsToStation) {
                throw new AppError("Item does not belong to this station", 400)
            }

            const activeConfigurationSnapshot = readConfigurationSnapshot(
                item.productionOverrideSnapshot ?? item.configurationSnapshot,
            )
            const stockUnits = resolveStockUnits({
                ...item,
                configurationSnapshot: activeConfigurationSnapshot,
                productionOverrideSnapshot: readConfigurationSnapshot(item.productionOverrideSnapshot),
            })

            const existingStocks = await tx.stationProductStock.findMany({
                where: {
                    stationId,
                    productId: item.productId,
                    OR: stockUnits.map((stockUnit) => ({
                        variantType: stockUnit.variantType,
                        variantKey: stockUnit.variantKey,
                    })),
                }
            })
            const stockByLookupKey = new Map(
                existingStocks.map((stock) => [`${stock.variantType}::${stock.variantKey}`, stock])
            )

            const missingUnits = stockUnits.filter((stockUnit) => {
                const existingStock = stockByLookupKey.get(`${stockUnit.variantType}::${stockUnit.variantKey}`)
                return !existingStock || existingStock.quantity < stockUnit.quantity
            })

            const partialConfiguratorCoverage =
                missingUnits.length > 0 && item.quantity === 1
                    ? buildPartialConfiguratorCoverage(activeConfigurationSnapshot, existingStocks)
                    : null

            if (missingUnits.length > 0 && !partialConfiguratorCoverage) {
                const missingLabel = missingUnits
                    .map((stockUnit) => `${stockUnit.variantLabel ?? stockUnit.variantKey} ×${stockUnit.quantity}`)
                    .join(", ")
                throw new AppError(
                    stockUnits.length > 1
                        ? `Stock configurateur insuffisant (${missingLabel})`
                        : "Insufficient stock",
                    400
                )
            }

            const stockUnitsToConsume = partialConfiguratorCoverage
                ? stockUnits
                    .map((stockUnit) => {
                        const coveredQuantity = partialConfiguratorCoverage.coverageByVariantKey.get(stockUnit.variantKey) ?? 0
                        if (coveredQuantity <= 0) return null

                        return {
                            ...stockUnit,
                            quantity: coveredQuantity,
                        }
                    })
                    .filter((stockUnit): stockUnit is ResolvedStockUnit => stockUnit !== null)
                : stockUnits

            const updatedStocks: Array<{
                productId: string
                productName: string
                newQuantity: number
                variantType: StockVariantType
                variantKey: string
                variantLabel: string | null
                delta: number
            }> = []

            for (const stockUnit of stockUnitsToConsume) {
                const existingStock = stockByLookupKey.get(`${stockUnit.variantType}::${stockUnit.variantKey}`)
                if (!existingStock) {
                    throw new AppError("Insufficient stock", 400)
                }

                const updatedStock = await tx.stationProductStock.update({
                    where: { id: existingStock.id },
                    data: { quantity: { decrement: stockUnit.quantity } }
                })

                updatedStocks.push({
                    productId: item.productId,
                    productName: item.product.name,
                    newQuantity: updatedStock.quantity,
                    variantType: stockUnit.variantType,
                    variantKey: stockUnit.variantKey,
                    variantLabel: stockUnit.variantLabel,
                    delta: -stockUnit.quantity,
                })
            }

            const station = await tx.station.findUnique({
                where: { id: stationId },
                include: { productionWorkflowSteps: { orderBy: { position: "asc" } } },
            })
            const workflowDto = toProductionWorkflowDto(station)
            const workflow = workflowDto
                ? (workflowDto.enabled === false
                    ? {
                        ...buildDefaultProductionWorkflowDto(),
                        enabled: false,
                        revision: workflowDto.revision ?? 1,
                    }
                    : workflowDto)
                : (station?.mainType === "PRODUCTION" ? buildDefaultProductionWorkflowDto() : null)
            const acknowledgedState = workflow ? getAcknowledgedProductionStepState(workflow) : null
            const nextStatus = partialConfiguratorCoverage
                ? OrderItemStatus.PREPARING
                : (acknowledgedState && workflow && acknowledgedState.index === workflow.steps.length - 1
                    ? OrderItemStatus.READY
                    : OrderItemStatus.PREPARING)

            // Passer l'item en PREPARING (le produit peut nécessiter réchauffage, dressage, etc.)
            const updatedItem = await tx.orderItem.update({
                where: { id: orderItemId },
                data: {
                    status: nextStatus,
                    takenById: userId,
                    revision: { increment: 1 },
                    productionStepIndex: acknowledgedState?.index ?? item.productionStepIndex ?? null,
                    productionStepCode: acknowledgedState?.code ?? item.productionStepCode ?? null,
                    productionStepLabel: acknowledgedState?.label ?? item.productionStepLabel ?? null,
                    productionWorkflowRevision: acknowledgedState?.workflowRevision ?? item.productionWorkflowRevision ?? null,
                    productionOverrideSnapshot: partialConfiguratorCoverage
                        ? (partialConfiguratorCoverage.remainingSnapshot as Prisma.InputJsonObject)
                        : Prisma.DbNull,
                    productionWorkflowSnapshot: workflow
                        ? buildProductionWorkflowSnapshot(workflow)
                        : item.productionWorkflowSnapshot ?? undefined,
                },
                include: {
                    product: true,
                    order: true,
                    takenBy: true
                }
            })

            await tx.orderItemLifecycleEvent.create({
                data: {
                    orderItemId,
                    eventType: nextStatus === OrderItemStatus.READY
                        ? LifecycleEventType.READY
                        : LifecycleEventType.ACKNOWLEDGED,
                    fromStatus: OrderItemStatus.PENDING,
                    toStatus: updatedItem.status,
                    fromProductionStepIndex: item.productionStepIndex ?? null,
                    toProductionStepIndex: updatedItem.productionStepIndex ?? null,
                    fromProductionStepCode: item.productionStepCode ?? null,
                    toProductionStepCode: updatedItem.productionStepCode ?? null,
                    actorId: userId,
                    actorName: actor?.displayName ?? actor?.username ?? actor?.email ?? null,
                    stationId,
                }
            })

            return {
                item,
                updatedItem,
                updatedStocks,
                actorName: actor?.displayName ?? actor?.username ?? actor?.email ?? null,
                workflowSnapshot: workflow ? buildProductionWorkflowSnapshot(workflow) : null,
                productionDisplay: buildOrderItemProductionDisplayData(updatedItem),
            }
        })

        // Émettre les événements (hors transaction)
        const t = tracked({ shopId, entity: "Station", actorUserId: userId, senderSocketId })

        await t.emit(
            "order_item.production_step_changed",
            {
                orderItemId,
                orderId: result.updatedItem.orderId,
                stationId: result.updatedItem.order?.stationId ?? null,
                cashSessionId: result.updatedItem.order?.cashSessionId ?? null,
                createdById: result.updatedItem.order?.createdById ?? null,
                previousStatus: "PENDING",
                newStatus: result.updatedItem.status,
                previousStepIndex: result.item.productionStepIndex ?? null,
                newStepIndex: result.updatedItem.productionStepIndex ?? null,
                previousStepCode: result.item.productionStepCode ?? null,
                newStepCode: result.updatedItem.productionStepCode ?? null,
                previousStepLabel: result.item.productionStepLabel ?? null,
                newStepLabel: result.updatedItem.productionStepLabel ?? null,
                productStationId: stationId,
                logisticsRouteId: result.updatedItem.logisticsRouteId ?? null,
                currentStepPosition: result.updatedItem.currentStepPosition ?? null,
                currentStepStationId: result.updatedItem.currentStepStationId ?? null,
                productionStepIndex: result.updatedItem.productionStepIndex ?? null,
                productionStepCode: result.updatedItem.productionStepCode ?? null,
                productionStepLabel: result.updatedItem.productionStepLabel ?? null,
                productionWorkflowRevision: result.updatedItem.productionWorkflowRevision ?? null,
                productionWorkflowSnapshot: result.workflowSnapshot,
                productionConfigurationSnapshot: result.productionDisplay.productionConfigurationSnapshot,
                stockCoverage: result.productionDisplay.stockCoverage,
                takenByName: result.actorName,
                servedFromStock: true,
            },
            orderItemId,
            result.updatedItem.revision
        )

        await t.emit(
            "order_item.status_changed",
            {
                orderItemId,
                orderId: result.updatedItem.orderId,
                stationId: result.updatedItem.order?.stationId ?? null,
                cashSessionId: result.updatedItem.order?.cashSessionId ?? null,
                createdById: result.updatedItem.order?.createdById ?? null,
                newStatus: result.updatedItem.status,
                previousStatus: "PENDING",
                productStationId: stationId,
                takenByName: result.actorName,
                logisticsRouteId: result.updatedItem.logisticsRouteId ?? null,
                currentStepPosition: result.updatedItem.currentStepPosition ?? null,
                currentStepStationId: result.updatedItem.currentStepStationId ?? null,
                productionStepIndex: result.updatedItem.productionStepIndex ?? null,
                productionStepCode: result.updatedItem.productionStepCode ?? null,
                productionStepLabel: result.updatedItem.productionStepLabel ?? null,
                productionWorkflowRevision: result.updatedItem.productionWorkflowRevision ?? null,
                productionWorkflowSnapshot: result.workflowSnapshot,
                productionConfigurationSnapshot: result.productionDisplay.productionConfigurationSnapshot,
                stockCoverage: result.productionDisplay.stockCoverage,
                servedFromStock: true
            },
            orderItemId,
            result.updatedItem.revision
        )

        for (const stockUpdate of result.updatedStocks) {
            await t.emit(
                "station.stock_updated",
                {
                    stationId,
                    ...stockUpdate,
                    reason: "used_for_order",
                    orderItemId
                },
                stationId,
                1
            )
        }

        const firstStockUpdate = result.updatedStocks[0] ?? null

        return {
            item: {
                ...result.updatedItem,
                productionConfigurationSnapshot: result.productionDisplay.productionConfigurationSnapshot,
                stockCoverage: result.productionDisplay.stockCoverage,
            },
            stock: firstStockUpdate
                ? {
                    productId: firstStockUpdate.productId,
                    productName: firstStockUpdate.productName,
                    newQuantity: firstStockUpdate.newQuantity,
                    variantType: firstStockUpdate.variantType,
                    variantKey: firstStockUpdate.variantKey,
                    variantLabel: firstStockUpdate.variantLabel,
                }
                : null,
            stockUpdates: result.updatedStocks,
        }
    },

    /**
     * Incrémenter manuellement le stock (produit préparé en avance).
     */
    async incrementStock(
        shopId: string,
        stationId: string,
        productId: string,
        quantity: number,
        userId: string,
        senderSocketId?: string
    ) {
        const product = await prisma.product.findFirst({
            where: { id: productId, shopId, stationId }
        })

        if (!product) {
            throw new AppError("Product not found or not assigned to this station", 404)
        }

        const stock = await prisma.stationProductStock.upsert({
            where: {
                stationId_productId_variantType_variantKey: {
                    stationId,
                    productId,
                    variantType: "STANDARD",
                    variantKey: "STANDARD",
                }
            },
            create: {
                stationId,
                productId,
                shopId,
                quantity,
                variantType: "STANDARD",
                variantKey: "STANDARD",
            },
            update: {
                quantity: { increment: quantity }
            }
        })

        const t = tracked({ shopId, entity: "Station", actorUserId: userId, senderSocketId })
        await t.emit(
            "station.stock_updated",
            {
                stationId,
                productId,
                productName: product.name,
                newQuantity: stock.quantity,
                variantType: "STANDARD",
                variantKey: "STANDARD",
                variantLabel: null,
                delta: quantity,
                reason: "manual"
            },
            stationId,
            1
        )

        return {
            productId,
            productName: product.name,
            newQuantity: stock.quantity,
            variantType: "STANDARD",
            variantKey: "STANDARD",
            variantLabel: null,
            delta: quantity
        }
    },

    /**
     * Décrémenter manuellement le stock (transaction atomique).
     */
    async decrementStock(
        shopId: string,
        stationId: string,
        productId: string,
        quantity: number,
        userId: string,
        senderSocketId?: string
    ) {
        const result = await prisma.$transaction(async (tx) => {
            const stock = await tx.stationProductStock.findUnique({
                where: {
                    stationId_productId_variantType_variantKey: {
                        stationId,
                        productId,
                        variantType: "STANDARD",
                        variantKey: "STANDARD",
                    }
                },
                include: { product: true }
            })

            if (!stock || stock.quantity < quantity) {
                throw new AppError("Insufficient stock", 400)
            }

            const updated = await tx.stationProductStock.update({
                where: { id: stock.id },
                data: { quantity: { decrement: quantity } }
            })

            return { stock, updated }
        })

        const t = tracked({ shopId, entity: "Station", actorUserId: userId, senderSocketId })
        await t.emit(
            "station.stock_updated",
            {
                stationId,
                productId,
                productName: result.stock.product.name,
                newQuantity: result.updated.quantity,
                variantType: "STANDARD",
                variantKey: "STANDARD",
                variantLabel: null,
                delta: -quantity,
                reason: "manual"
            },
            stationId,
            1
        )

        return {
            productId,
            productName: result.stock.product.name,
            newQuantity: result.updated.quantity,
            variantType: "STANDARD",
            variantKey: "STANDARD",
            variantLabel: null,
            delta: -quantity
        }
    }
}
