/**
 * Antagandeprofiler för matlagning (Fas 3 §6.2).
 * Rensa, deterministiska funktioner för att uppdatera per-hushålls-per-ingrediens-profiler
 * utifrån faktiska svar efter en cooking session.
 */

export interface ProfileUpdateInput {
  householdId: string;
  canonicalIngredientId: string;
  plannedPortions: number;
  actualPortionsEaten: number;
  leftoverEstimatePortions: number;
  sessionId: string;
  date: string;
}

export interface ExistingProfile {
  averageEatenPortions: number | null;
  averageLeftoverPortions: number | null;
  observationCount: number;
  lastSessionAnswers?: Array<{ sessionId: string; eaten: number; leftovers: number; date: string }> | null;
}

/**
 * Beräkna nya profilvärden med exponentiellt glidande medelvärde.
 * alpha = 1 / (observationCount + 1) ger jämn viktning över tid.
 */
export function updateCookingAssumptionProfile(
  input: ProfileUpdateInput,
  existing: ExistingProfile,
): {
  averageEatenPortions: number;
  averageLeftoverPortions: number;
  observationCount: number;
  lastSessionAnswers: Array<{ sessionId: string; eaten: number; leftovers: number; date: string }>;
} {
  const eaten = clamp(input.actualPortionsEaten, 0, input.plannedPortions);
  const leftovers = clamp(input.leftoverEstimatePortions, 0, input.plannedPortions - eaten);

  const prevEaten = existing.averageEatenPortions ?? eaten;
  const prevLeftovers = existing.averageLeftoverPortions ?? leftovers;
  const prevCount = existing.observationCount ?? 0;

  const alpha = 1 / (prevCount + 1);
  const averageEatenPortions = round2(prevEaten + alpha * (eaten - prevEaten));
  const averageLeftoverPortions = round2(prevLeftovers + alpha * (leftovers - prevLeftovers));
  const observationCount = prevCount + 1;

  const history = existing.lastSessionAnswers ?? [];
  const lastSessionAnswers = [
    { sessionId: input.sessionId, eaten, leftovers, date: input.date },
    ...history,
  ].slice(0, 10);

  return { averageEatenPortions, averageLeftoverPortions, observationCount, lastSessionAnswers };
}

/**
 * Återställ en antagandeprofil genom att ta bort ett specifikt sessions-id
 * från historiken och räkna om medelvärdena deterministiskt från resterande
 * observationer. Ren funktion – alla beroenden är explicita argument.
 */
export function rollbackCookingAssumptionProfile(
  sessionId: string,
  existing: ExistingProfile,
): {
  averageEatenPortions: number | null;
  averageLeftoverPortions: number | null;
  observationCount: number;
  lastSessionAnswers: Array<{ sessionId: string; eaten: number; leftovers: number; date: string }>;
} {
  const history = (existing.lastSessionAnswers ?? []).filter((a) => a.sessionId !== sessionId);

  if (history.length === 0) {
    return {
      averageEatenPortions: null,
      averageLeftoverPortions: null,
      observationCount: 0,
      lastSessionAnswers: [],
    };
  }

  // Räkna om EMA från scratch i kronologisk ordning (äldst först).
  const chronological = [...history].reverse();
  let avgEaten = chronological[0]!.eaten;
  let avgLeftovers = chronological[0]!.leftovers;

  for (let i = 1; i < chronological.length; i++) {
    const alpha = 1 / (i + 1);
    const a = chronological[i]!;
    avgEaten = round2(avgEaten + alpha * (a.eaten - avgEaten));
    avgLeftovers = round2(avgLeftovers + alpha * (a.leftovers - avgLeftovers));
  }

  return {
    averageEatenPortions: avgEaten,
    averageLeftoverPortions: avgLeftovers,
    observationCount: history.length,
    lastSessionAnswers: history,
  };
}

function clamp(n: number, min: number, max: number): number {
  return Math.max(min, Math.min(max, n));
}

function round2(n: number): number {
  return Math.round(n * 100) / 100;
}
