import type {
  Cuisine,
  MealType,
  MemoryItem,
  NutritionValues,
  RecipeTag,
  Season,
  TasteSignal,
  WeatherHint,
} from "@app/shared-types";
import type { CoverageResult } from "@app/recipe-engine";

/** Hushållsspecifikt förbrukningsantagande per ingrediens. */
export interface CookingAssumption {
  canonicalIngredientId: string;
  averageEatenPortions: number | null;
  averageLeftoverPortions: number | null;
  observationCount: number;
}

/** Provenienspost: varför valdes detta förslag? */
export interface ProvenanceEntry {
  key: string;
  args: Record<string, string | number>;
}

/** Kandidat som poängsätts. Säkerhetsfiltrering har redan skett (blockers borta). */
export interface RecommendationCandidate {
  recipeId: string;
  titleSv: string;
  cuisine: Cuisine;
  tags: RecipeTag[];
  totalTimeMinutes: number;
  nutritionPerPortion: NutritionValues;
  estimatedCostMinorPerPortion?: number | null;
  ratingAverage?: number | null;
  ratingCount: number;
  peakSeasons: Season[];
  holidayTags: string[];
  spiceLevel: number;
  coverage: CoverageResult;
  /** Dagar sedan hushållet senast lagade receptet (null = aldrig). */
  daysSinceLastCooked?: number | null;
  /** Hushållets snittbetyg på receptet, om finns. */
  householdRating?: number | null;
  /** Kanoniska ingrediens-id:n för receptet (inklusive valfria) – för tasteFit/cookingAssumptionFit. */
  ingredientIds?: string[];
}

export interface RecommendationContext {
  mealType: MealType;
  persons: number;
  maxMinutes?: number | undefined;
  maxCostMinorPerPortion?: number | undefined;
  /** Proteinlucka kvar i dag (g) för den som frågar – styr proteinfit. */
  remainingProteinG?: number | undefined;
  /** Kalorier kvar i dag – recept långt över straffas mjukt. */
  remainingKcal?: number | undefined;
  currentSeason: Season;
  activeHolidayTags: string[];
  weather?: WeatherHint | undefined;
  isWeekday: boolean;
  isTrainingDay?: boolean | undefined;
  favoriteCuisines: Cuisine[];
  /** Tolkade "jag är sugen på"-taggar (spec §19), redan normaliserade. */
  cravingTags?: string[] | undefined;
  cravingCuisine?: Cuisine | undefined;
  cravingMaxKcal?: number | undefined;
  /** Personligt minne; bara inläst om personalization-samtycke granted. */
  memoryItems?: MemoryItem[];
  /** Smaksignaler; bara inläst om personalization-samtycke granted. */
  tasteSignals?: TasteSignal[];
  /** Förbrukningsantaganden; bara inläst om personalization-samtycke granted. */
  cookingAssumptions?: CookingAssumption[];
  /** Hård grind: false = ignorera alla personliga signaler. */
  personalizationEnabled: boolean;
}

export interface ScoredRecommendation {
  recipeId: string;
  titleSv: string;
  score: number;
  /** Delpoäng för transparens och evals. */
  parts: Record<string, number>;
  whySv: string;
  missingIngredients: string[];
  usesExpiring: Array<{ nameSv: string; daysLeft: number | null }>;
  coveragePercent: number;
  /** Proveniensposter som `whySv` byggs från. */
  provenance: ProvenanceEntry[];
}

/** Vikter – justerbara via feature flags/admin utan koddeploy. */
export interface ScoringWeights {
  coverage: number;
  expiry: number;
  nutritionFit: number;
  taste: number;
  rating: number;
  season: number;
  holiday: number;
  time: number;
  budget: number;
  variety: number;
  weather: number;
  craving: number;
  /** Nya S1-vikter; 0 om personalisering är av. */
  memoryFit: number;
  tasteFit: number;
  cookingAssumptionFit: number;
}

export const DEFAULT_WEIGHTS: ScoringWeights = {
  coverage: 30,
  expiry: 20,
  nutritionFit: 12,
  taste: 10,
  rating: 8,
  season: 4,
  holiday: 6,
  time: 8,
  budget: 6,
  variety: 6,
  weather: 3,
  craving: 15,
  memoryFit: 6,
  tasteFit: 6,
  cookingAssumptionFit: 4,
};

/** Vikter när personalisering är avslagen – exakt samma som tidigare. */
export const NON_PERSONALIZED_WEIGHTS: ScoringWeights = {
  ...DEFAULT_WEIGHTS,
  memoryFit: 0,
  tasteFit: 0,
  cookingAssumptionFit: 0,
};

/** Tillåtna vyer för "Vad ska vi äta?". */
export type RecommendationView = "default" | "taste" | "health" | "pantry";

export const RECOMMENDATION_VIEWS: RecommendationView[] = ["default", "taste", "health", "pantry"];

/** Fördefinierade vikter för smak-vyn (S4). */
export const TASTE_VIEW_WEIGHTS: ScoringWeights = {
  coverage: 20,
  expiry: 10,
  nutritionFit: 5,
  taste: 25,
  rating: 10,
  season: 3,
  holiday: 3,
  time: 5,
  budget: 3,
  variety: 3,
  weather: 1,
  craving: 25,
  memoryFit: 12,
  tasteFit: 12,
  cookingAssumptionFit: 6,
};

/** Fördefinierade vikter för hälsa-vyn (S4) — stödjande, icke-restriktiv (R7). */
export const HEALTH_VIEW_WEIGHTS: ScoringWeights = {
  coverage: 20,
  expiry: 12,
  nutritionFit: 35,
  taste: 5,
  rating: 6,
  season: 4,
  holiday: 4,
  time: 6,
  budget: 3,
  variety: 4,
  weather: 2,
  craving: 5,
  memoryFit: 3,
  tasteFit: 3,
  cookingAssumptionFit: 4,
};

/** Fördefinierade vikter för lager-vyn (S4). */
export const PANTRY_VIEW_WEIGHTS: ScoringWeights = {
  coverage: 45,
  expiry: 35,
  nutritionFit: 5,
  taste: 4,
  rating: 4,
  season: 2,
  holiday: 2,
  time: 6,
  budget: 4,
  variety: 2,
  weather: 1,
  craving: 5,
  memoryFit: 4,
  tasteFit: 4,
  cookingAssumptionFit: 8,
};

/** Hämta vikter för en specifik vy. */
export function viewWeights(view: RecommendationView): ScoringWeights {
  switch (view) {
    case "taste":
      return TASTE_VIEW_WEIGHTS;
    case "health":
      return HEALTH_VIEW_WEIGHTS;
    case "pantry":
      return PANTRY_VIEW_WEIGHTS;
    default:
      return DEFAULT_WEIGHTS;
  }
}

/** Nollställ de personliga axlarna i en viktmängd — används när samtycke saknas. */
export function depersonalize(weights: ScoringWeights): ScoringWeights {
  return { ...weights, memoryFit: 0, tasteFit: 0, cookingAssumptionFit: 0 };
}
