import type { EventType, Unit } from "@app/shared-types";

/**
 * Typade payloads för domänhändelser (spec §55).
 * Events skrivs i outbox-tabellen (domain_events) i samma transaktion som
 * affärsdatan och konsumeras asynkront av worker (memory, analytics, training).
 */
export interface EventPayloadMap {
  PRODUCT_ADDED: {
    inventoryItemId: string;
    canonicalIngredientId?: string | null;
    quantity: number;
    unit: Unit;
    source: string;
  };
  PRODUCT_UPDATED: { inventoryItemId: string; changes: Record<string, unknown> };
  PRODUCT_CONSUMED: {
    inventoryItemId: string;
    quantity: number;
    unit: Unit;
    refType?: string | null;
  };
  PRODUCT_DISCARDED: {
    inventoryItemId: string;
    quantity: number;
    unit: Unit;
    valueMinor?: number | null;
    reason?: string | null;
  };
  RECIPE_COOKED: { recipeId: string; portions: number; mealBoxPortions: number };
  RECIPE_RATED: { recipeId: string; stars: number; feedbackTags: string[] };
  RECIPE_CREATED: { recipeId: string; sourceType: string };
  RECIPE_FORKED: { recipeId: string; forkedFromRecipeId: string };
  MEAL_LOGGED: { mealId: string; mealType: string; kcal: number; source: string };
  MEAL_PHOTO_ANALYZED: { scanJobId: string; matched: boolean; kcalMostLikely?: number | null };
  HOUSEHOLD_MEMBER_ADDED: { householdId: string; newUserId: string; role: string };
  SUBSCRIPTION_STARTED: { subscriptionId: string; plan: string; provider: string };
  SUBSCRIPTION_CHANGED: { subscriptionId: string; status: string };
  AI_CORRECTED: { scanJobId?: string | null; taskType: string; field: string };
  MEMORY_UPDATED: { memoryItemId: string; kind: string; origin: string };
  SHOPPING_COMPLETED: { shoppingListId: string; itemsAdded: number };
  WEEK_PLAN_UPDATED: { weekPlanId: string; reason?: string | null };
  MEAL_BOX_CREATED: { mealBoxId: string; portions: number };
  MEAL_BOX_CONSUMED: { mealBoxId: string; portions: number };
}

/** Kontroll i kompileringstid att kartan täcker alla EventType. */
type AssertCoversAll = EventType extends keyof EventPayloadMap ? true : never;
const _coversAll: AssertCoversAll = true;
void _coversAll;

export interface NewDomainEvent<T extends EventType = EventType> {
  type: T;
  payload: T extends keyof EventPayloadMap ? EventPayloadMap[T] : never;
  userId?: string | undefined;
  householdId?: string | undefined;
  correlationId?: string | undefined;
}

/** Hjälpare med full typinferens: makeEvent("RECIPE_COOKED", {...}). */
export function makeEvent<T extends EventType>(
  type: T,
  payload: T extends keyof EventPayloadMap ? EventPayloadMap[T] : never,
  scope: { userId?: string; householdId?: string; correlationId?: string } = {},
): NewDomainEvent<T> {
  return { type, payload, ...scope };
}
