import type { AamosTaskType } from "./tasks.js"; /** * Deterministiska mock-svar per uppgiftstyp. Realistiska nog för att bygga * UI-flöden och tester mot – inklusive osäkerhetsfall (requiresConfirmation, * lågt confidence) så att korrigerings-UX:et alltid övas (spec §61.4–5). */ export function mockOutputFor(taskType: AamosTaskType, input: unknown): unknown { switch (taskType) { case "ANALYZE_FRIDGE_IMAGE": case "ANALYZE_PANTRY_IMAGE": return { items: [ { detectedName: "mjölk", canonicalIngredientId: "milk_3", brand: "Arla", estimatedQuantity: 0.7, unit: "LITER", bestBeforeDate: null, confidence: 0.84, requiresConfirmation: true, boundingBox: null, }, { detectedName: "crème fraîche", canonicalIngredientId: "creme_fraiche", brand: null, estimatedQuantity: 1, unit: "COUNT", bestBeforeDate: null, confidence: 0.61, requiresConfirmation: true, boundingBox: null, }, { detectedName: "okänd burk", canonicalIngredientId: null, brand: null, estimatedQuantity: null, unit: null, bestBeforeDate: null, confidence: 0.2, requiresConfirmation: true, boundingBox: null, }, ], imageQualityIssues: [], }; case "ANALYZE_MEAL_IMAGE": { const hasContext = typeof input === "object" && input !== null && (input as { recipeContext?: unknown }).recipeContext != null; return { matchesRecipeContext: hasContext ? true : null, portionFractionEstimate: 1, kcalRange: { min: 650, max: 750, mostLikely: 700 }, components: [ { name: "kycklingfilé", canonicalIngredientId: "chicken_breast", estimatedGrams: 150, confidence: 0.8, }, { name: "ris", canonicalIngredientId: "rice_white", estimatedGrams: 180, confidence: 0.75, }, ], confidence: 0.72, }; } case "READ_RECEIPT": return { storeName: "ICA Supermarket", purchaseDate: "2026-08-01", lines: [ { rawText: "KYCKL FILE 925G", normalizedName: "Kycklingfilé 925 g", canonicalIngredientId: "chicken_breast", quantity: 925, unit: "GRAM", unitPriceMinor: 11990, totalPriceMinor: 11990, isDiscount: false, confidence: 0.9, }, { rawText: "MELLANMJ 1.5L", normalizedName: "Mellanmjölk 1,5 l", canonicalIngredientId: "milk_1_5", quantity: 1.5, unit: "LITER", unitPriceMinor: 1890, totalPriceMinor: 1890, isDiscount: false, confidence: 0.87, }, ], totalMinor: 13880, discountTotalMinor: 0, confidence: 0.85, }; case "READ_NUTRITION_LABEL": return { basis: "per_100_g", values: { kcal: 106, proteinG: 22, carbsG: 0, fatG: 2, saturatedFatG: 0.6, fiberG: 0, sugarG: 0, saltG: 0.2, }, ingredientsText: "Kycklingfilé (100 %)", allergensDeclared: [], gtin: null, productName: "Kycklingfilé", brand: null, confidence: 0.88, }; case "READ_EXPIRY_DATE": return { date: "2026-08-06", dateKind: "best_before", confidence: 0.9 }; case "NORMALIZE_PRODUCTS": { const rawNames = typeof input === "object" && input !== null ? ((input as { rawNames?: string[] }).rawNames ?? []) : []; return { matches: rawNames.map((raw) => ({ raw, canonicalIngredientId: null, normalizedName: raw.toLowerCase(), confidence: 0.4, })), }; } case "DEDUPLICATE_INVENTORY": return { duplicateGroups: [] }; case "STRUCTURE_RECIPE_TEXT": return { titleSv: "Snabb kycklingpasta", descriptionSv: "Krämig vardagspasta med kyckling och spenat.", ingredients: [ { rawText: "400 g kycklingfilé", canonicalIngredientId: "chicken_breast", displayNameSv: "Kycklingfilé", quantity: 400, unit: "GRAM", optional: false, confidence: 0.9, }, { rawText: "300 g pasta", canonicalIngredientId: "pasta_dry", displayNameSv: "Pasta", quantity: 300, unit: "GRAM", optional: false, confidence: 0.9, }, ], steps: [ { instructionSv: "Koka pastan enligt anvisning.", timerSeconds: 600, temperatureC: null }, { instructionSv: "Stek kycklingen tills genomstekt.", timerSeconds: null, temperatureC: null, }, ], prepTimeMinutes: 10, cookTimeMinutes: 15, portions: 4, suggestedCuisine: "italian", suggestedMealTypes: ["dinner"], confidence: 0.82, }; case "GENERATE_RECIPE_OPTIONS": return { suggestions: [ { titleSv: "Krämig kycklingwok med grönsaker", descriptionSv: "Snabb wok på det som finns hemma.", ingredients: [ { canonicalIngredientId: "chicken_breast", displayNameSv: "Kycklingfilé", quantity: 400, unit: "GRAM", }, { canonicalIngredientId: "rice_white", displayNameSv: "Ris", quantity: 3, unit: "DECILITER", }, ], steps: ["Koka riset.", "Woka kycklingen.", "Blanda och servera."], estimatedTimeMinutes: 25, confidence: 0.7, }, ], }; case "RANK_RECIPES": { const ids = typeof input === "object" && input !== null ? ((input as { candidateIds?: string[] }).candidateIds ?? []) : []; return { rankedIds: ids, rationaleSv: null }; } case "PARSE_CRAVING": return { tags: ["creamy"], cuisine: null, maxKcal: null, confidence: 0.6 }; case "UPDATE_USER_MEMORY": return { memoryUpdates: [] }; case "GENERATE_WEEK_PLAN": return { entries: [], confidence: 0.5 }; case "MODERATE_RECIPE": return { flags: [], recommendation: "approve", confidence: 0.9 }; case "EXPORT_TRAINING_SAMPLE": { const samples = typeof input === "object" && input !== null ? ((input as { samples?: unknown[] }).samples ?? []) : []; return { batchId: `mock-batch-${Date.now()}`, accepted: samples.length, rejected: 0, }; } case "TRANSLATE_RECIPE": { // Deterministisk pseudo-översättning: bevarar alla tal och stegstruktur, // markerar texten med målspråket så flödet är testbart utan riktig AI. const inp = input as { targetLanguageTag: string; title: string; description: string | null; storageGuidance: string | null; steps: { stepNumber: number; instruction: string; tip: string | null }[]; }; const tag = `[${inp.targetLanguageTag}]`; return { title: `${tag} ${inp.title}`, description: inp.description ? `${tag} ${inp.description}` : null, storageGuidance: inp.storageGuidance ? `${tag} ${inp.storageGuidance}` : null, steps: inp.steps.map((s) => ({ stepNumber: s.stepNumber, instruction: `${tag} ${s.instruction}`, tip: s.tip ? `${tag} ${s.tip}` : null, })), confidence: 0.85, }; } } }