import type {
  ProvenanceEntry,
  RecommendationCandidate,
  RecommendationContext,
} from "./types.js";
import { renderProvenance } from "./provenance-templates.js";

import type { LanguageTag } from "./provenance-templates.js";

interface WhyTemplates {
  coverage100: string;
  coveragePct: string;
  coverageLow: string;
  expiringToday: string;
  expiringTomorrow: string;
  expiringDays: string;
  protein: string;
  trainingDay: string;
  householdRating: string;
  holiday: string;
  season: string;
  time: string;
  budget: string;
  craving: string;
  fallback: string;
}

const WHY_TEMPLATES: Record<LanguageTag, WhyTemplates> = {
  sv: {
    coverage100: "Ni har alla ingredienser hemma.",
    coveragePct: "Ni har {{pct}} % av ingredienserna hemma.",
    coverageLow: "Ni har {{pct}} % av ingredienserna – resten hamnar på inköpslistan.",
    expiringToday: "{{ingredient}} bör användas i dag.",
    expiringTomorrow: "{{ingredient}} bör användas senast i morgon.",
    expiringDays: "{{ingredient}} bör användas inom {{days}} dagar.",
    protein: "Rätten ger {{protein}} gram protein per portion.",
    trainingDay: "Bra val på en träningsdag.",
    householdRating: "Liknande rätter har fått höga betyg av hushållet.",
    holiday: "Passar den kommande högtiden.",
    season: "Råvarorna är i säsong just nu.",
    time: "Klar på {{minutes}} minuter.",
    budget: "Cirka {{cost}} kr per portion.",
    craving: "Matchar det du är sugen på.",
    fallback: "En balanserad rätt som passar er profil.",
  },
  en: {
    coverage100: "You have all the ingredients at home.",
    coveragePct: "You have {{pct}} % of the ingredients at home.",
    coverageLow: "You have {{pct}} % of the ingredients – the rest goes on the shopping list.",
    expiringToday: "{{ingredient}} should be used today.",
    expiringTomorrow: "{{ingredient}} should be used by tomorrow.",
    expiringDays: "{{ingredient}} should be used within {{days}} days.",
    protein: "The dish provides {{protein}} grams of protein per portion.",
    trainingDay: "A good choice for a training day.",
    householdRating: "Similar dishes have been rated highly by your household.",
    holiday: "Fits the upcoming holiday.",
    season: "The ingredients are in season right now.",
    time: "Ready in {{minutes}} minutes.",
    budget: "About {{cost}} per portion.",
    craving: "Matches what you’re craving.",
    fallback: "A balanced dish that fits your profile.",
  },
  es: {
    coverage100: "Tenéis todos los ingredientes en casa.",
    coveragePct: "Tenéis el {{pct}} % de los ingredientes en casa.",
    coverageLow: "Tenéis el {{pct}} % de los ingredientes; el resto irá a la lista de la compra.",
    expiringToday: "{{ingredient}} debería usarse hoy.",
    expiringTomorrow: "{{ingredient}} debería usarse como máximo mañana.",
    expiringDays: "{{ingredient}} debería usarse en {{days}} días.",
    protein: "El plato aporta {{protein}} gramos de proteína por ración.",
    trainingDay: "Buena elección para un día de entrenamiento.",
    householdRating: "Platos similares han sido valorados positivamente por tu hogar.",
    holiday: "Encaja con la próxima festividad.",
    season: "Los ingredientes están de temporada ahora mismo.",
    time: "Listo en {{minutes}} minutos.",
    budget: "Aproximadamente {{cost}} por ración.",
    craving: "Encaja con lo que te apetece.",
    fallback: "Un plato equilibrado que encaja con tu perfil.",
  },
  it: {
    coverage100: "Avete tutti gli ingredienti a casa.",
    coveragePct: "Avete il {{pct}} % degli ingredienti a casa.",
    coverageLow: "Avete il {{pct}} % degli ingredienti; il resto finisce sulla lista della spesa.",
    expiringToday: "{{ingredient}} va usato oggi.",
    expiringTomorrow: "{{ingredient}} va usato al più tardi domani.",
    expiringDays: "{{ingredient}} va usato entro {{days}} giorni.",
    protein: "Il piatto fornisce {{protein}} grammi di proteine a porzione.",
    trainingDay: "Buona scelta per un giorno di allenamento.",
    householdRating: "Piatti simili sono stati valutati positivamente dalla tua famiglia.",
    holiday: "Perfetto per la prossima festività.",
    season: "Gli ingredienti sono di stagione in questo momento.",
    time: "Pronto in {{minutes}} minuti.",
    budget: "Circa {{cost}} a porzione.",
    craving: "Corrisponde a ciò che ti va.",
    fallback: "Un piatto equilibrato che si adatta al tuo profilo.",
  },
  de: {
    coverage100: "Ihr habt alle Zutaten zu Hause.",
    coveragePct: "Ihr habt {{pct}} % der Zutaten zu Hause.",
    coverageLow: "Ihr habt {{pct}} % der Zutaten; der Rest kommt auf die Einkaufsliste.",
    expiringToday: "{{ingredient}} sollte heute verwendet werden.",
    expiringTomorrow: "{{ingredient}} sollte spätestens morgen verwendet werden.",
    expiringDays: "{{ingredient}} sollte innerhalb von {{days}} Tagen verwendet werden.",
    protein: "Das Gericht liefert {{protein}} Gramm Protein pro Portion.",
    trainingDay: "Gute Wahl für einen Trainingstag.",
    householdRating: "Ähnliche Gerichte wurden von deinem Haushalt gut bewertet.",
    holiday: "Passt zum bevorstehenden Feiertag.",
    season: "Die Zutaten sind gerade saisonal.",
    time: "Fertig in {{minutes}} Minuten.",
    budget: "Etwa {{cost}} pro Portion.",
    craving: "Passt zu dem, worauf du Lust hast.",
    fallback: "Ein ausgewogenes Gericht, das zu deinem Profil passt.",
  },
  fr: {
    coverage100: "Vous avez tous les ingrédients à la maison.",
    coveragePct: "Vous avez {{pct}} % des ingrédients à la maison.",
    coverageLow: "Vous avez {{pct}} % des ingrédients; le reste ira sur la liste de courses.",
    expiringToday: "{{ingredient}} devrait être utilisé aujourd'hui.",
    expiringTomorrow: "{{ingredient}} devrait être utilisé au plus tard demain.",
    expiringDays: "{{ingredient}} devrait être utilisé dans {{days}} jours.",
    protein: "Le plat apporte {{protein}} grammes de protéines par portion.",
    trainingDay: "Bon choix pour un jour d'entraînement.",
    householdRating: "Des plats similaires ont été bien notés par votre foyer.",
    holiday: "Convient à la prochaine fête.",
    season: "Les ingrédients sont de saison en ce moment.",
    time: "Prêt en {{minutes}} minutes.",
    budget: "Environ {{cost}} par portion.",
    craving: "Correspond à ce dont vous avez envie.",
    fallback: "Un plat équilibré qui correspond à votre profil.",
  },
  da: {
    coverage100: "I har alle ingredienserne hjemme.",
    coveragePct: "I har {{pct}} % af ingredienserne hjemme.",
    coverageLow: "I har {{pct}} % af ingredienserne; resten kommer på indkøbslisten.",
    expiringToday: "{{ingredient}} bør bruges i dag.",
    expiringTomorrow: "{{ingredient}} bør bruges senest i morgen.",
    expiringDays: "{{ingredient}} bør bruges inden for {{days}} dage.",
    protein: "Retten giver {{protein}} gram protein pr. portion.",
    trainingDay: "Et godt valg på en træningsdag.",
    householdRating: "Lignende retter er blevet bedømt højt af husstanden.",
    holiday: "Passer til den kommende højtid.",
    season: "Råvarerne er i sæson lige nu.",
    time: "Klar på {{minutes}} minutter.",
    budget: "Cirka {{cost}} pr. portion.",
    craving: "Matcher det, du har lyst til.",
    fallback: "En balanceret ret, der passer til din profil.",
  },
  nb: {
    coverage100: "Dere har alle ingrediensene hjemme.",
    coveragePct: "Dere har {{pct}} % av ingrediensene hjemme.",
    coverageLow: "Dere har {{pct}} % av ingrediensene; resten kommer på handlelisten.",
    expiringToday: "{{ingredient}} bør brukes i dag.",
    expiringTomorrow: "{{ingredient}} bør brukes senest i morgen.",
    expiringDays: "{{ingredient}} bør brukes innen {{days}} dager.",
    protein: "Retten gir {{protein}} gram protein per porsjon.",
    trainingDay: "Et godt valg på en treningsdag.",
    householdRating: "Lignende retter er blitt vurdert høyt av husstanden.",
    holiday: "Passer til den kommende høytiden.",
    season: "Råvarene er i sesong akkurat nå.",
    time: "Klar på {{minutes}} minutter.",
    budget: "Omtrent {{cost}} per porsjon.",
    craving: "Matcher det du har lyst på.",
    fallback: "En balansert rett som passer profilen din.",
  },
  fi: {
    coverage100: "Teillä on kaikki ainekset kotona.",
    coveragePct: "Teillä on {{pct}} % aineksista kotona.",
    coverageLow: "Teillä on {{pct}} % aineksista; loput menevät ostoslistalle.",
    expiringToday: "{{ingredient}} tulisi käyttää tänään.",
    expiringTomorrow: "{{ingredient}} tulisi käyttää viimeistään huomenna.",
    expiringDays: "{{ingredient}} tulisi käyttää {{days}} päivän kuluessa.",
    protein: "Ruoka antaa {{protein}} grammaa proteiinia annosta kohti.",
    trainingDay: "Hyvä valinta treenipäivälle.",
    householdRating: "Samankaltaiset ruoat on arvioitu korkealle taloudessasi.",
    holiday: "Sopii lähestyvään juhlapäivään.",
    season: "Ainekset ovat sesongissa juuri nyt.",
    time: "Valmista {{minutes}} minuutissa.",
    budget: "Noin {{cost}} annosta kohti.",
    craving: "Vastaa sitä, mitä haluat.",
    fallback: "Tasapainoinen ruoka, joka sopii profiilisi.",
  },
  nl: {
    coverage100: "Jullie hebben alle ingrediënten thuis.",
    coveragePct: "Jullie hebben {{pct}} % van de ingrediënten thuis.",
    coverageLow: "Jullie hebben {{pct}} % van de ingrediënten; de rest komt op het boodschappenlijstje.",
    expiringToday: "{{ingredient}} moet vandaag gebruikt worden.",
    expiringTomorrow: "{{ingredient}} moet uiterlijk morgen gebruikt worden.",
    expiringDays: "{{ingredient}} moet binnen {{days}} dagen gebruikt worden.",
    protein: "Het gerecht levert {{protein}} gram eiwit per portie.",
    trainingDay: "Een goede keuze voor een trainingdag.",
    householdRating: "Vergelijkbare gerechten zijn hoog beoordeeld door je huishouden.",
    holiday: "Past bij de komende feestdag.",
    season: "De ingrediënten zijn nu in het seizoen.",
    time: "Klaar in {{minutes}} minuten.",
    budget: "Ongeveer {{cost}} per portie.",
    craving: "Past bij waar je zin in hebt.",
    fallback: "Een evenwichtig gerecht dat bij je profiel past.",
  },
  pl: {
    coverage100: "Macie w domu wszystkie składniki.",
    coveragePct: "Macie w domu {{pct}} % składników.",
    coverageLow: "Macie w domu {{pct}} % składników; reszta trafi na listę zakupów.",
    expiringToday: "{{ingredient}} należy użyć dzisiaj.",
    expiringTomorrow: "{{ingredient}} należy użyć najpóźniej jutro.",
    expiringDays: "{{ingredient}} należy użyć w ciągu {{days}} dni.",
    protein: "Danie dostarcza {{protein}} gramów białka na porcję.",
    trainingDay: "Dobry wybór na dzień treningowy.",
    householdRating: "Podobne dania zostały wysoko ocenione przez Twoje gospodarstwo domowe.",
    holiday: "Pasuje do zbliżającego się święta.",
    season: "Składniki są teraz w sezonie.",
    time: "Gotowe w {{minutes}} minut.",
    budget: "Około {{cost}} za porcję.",
    craving: "Pasuje do tego, na co masz ochotę.",
    fallback: "Zrównoważone danie, które pasuje do Twojego profilu.",
  },
  pt: {
    coverage100: "Tens todos os ingredientes em casa.",
    coveragePct: "Tens {{pct}} % dos ingredientes em casa.",
    coverageLow: "Tens {{pct}} % dos ingredientes; o resto vai para a lista de compras.",
    expiringToday: "{{ingredient}} deve ser usado hoje.",
    expiringTomorrow: "{{ingredient}} deve ser usado até amanhã.",
    expiringDays: "{{ingredient}} deve ser usado em {{days}} dias.",
    protein: "O prato fornece {{protein}} gramas de proteína por porção.",
    trainingDay: "Boa escolha para um dia de treino.",
    householdRating: "Pratos semelhantes foram bem avaliados pelo teu agregado.",
    holiday: "Combina com o próximo feriado.",
    season: "Os ingredientes estão na época neste momento.",
    time: "Pronto em {{minutes}} minutos.",
    budget: "Aproximadamente {{cost}} por porção.",
    craving: "Combina com o que te apetece.",
    fallback: "Um prato equilibrado que se adequa ao teu perfil.",
  },
};

function getTemplates(lang: string): WhyTemplates {
  return WHY_TEMPLATES[(lang.split("-")[0] ?? "sv") as LanguageTag] ?? WHY_TEMPLATES.sv;
}

/** Returnerar de språk som why-mallarna täcker. */
export function whyTemplateLanguages(): LanguageTag[] {
  return Object.keys(WHY_TEMPLATES) as LanguageTag[];
}

function render(template: string, vars: Record<string, string | number>): string {
  return template.replace(/\{\{(\w+)\}\}/g, (_m, key) => String(vars[key] ?? ""));
}

/**
 * "Varför rekommenderar vi detta?" (spec §18, S1).
 * Bygger en ärlig, konkret förklaring ur:
 * 1. Grundade delpoäng (täckning, utgångsdatum, etc.).
 * 2. Personaliserings-mallar från provenans (endast om samtycke granted).
 *
 * Alla användarvisningstexter kommer från mallar, inte fri AI-text.
 * R7: näringsrelaterad copy är positiv/stödjande, aldrig restriktiv.
 */
export function buildWhy(
  candidate: RecommendationCandidate,
  ctx: RecommendationContext,
  parts: Record<string, number>,
  provenance: ProvenanceEntry[] = [],
  languageTag = "sv-SE",
): string {
  const t = getTemplates(languageTag);
  const sentences: string[] = [];

  const pct = Math.round(candidate.coverage.coverage * 100);
  if (pct >= 100) {
    sentences.push(t.coverage100);
  } else if (pct >= 60) {
    sentences.push(render(t.coveragePct, { pct }));
  } else if (pct > 0) {
    sentences.push(render(t.coverageLow, { pct }));
  }

  const urgent = candidate.coverage.expiringUsed
    .filter((m) => m.mostUrgentDaysLeft != null)
    .sort((a, b) => (a.mostUrgentDaysLeft ?? 99) - (b.mostUrgentDaysLeft ?? 99))[0];
  if (urgent) {
    const days = urgent.mostUrgentDaysLeft ?? 0;
    const tpl = days <= 0 ? t.expiringToday : days === 1 ? t.expiringTomorrow : t.expiringDays;
    sentences.push(render(tpl, { ingredient: capitalize(urgent.displayNameSv), days }));
  }

  // R7: positiv näringsframing
  const protein = Math.round(candidate.nutritionPerPortion.proteinG);
  if ((parts.nutritionFit ?? 0) >= 0.7 && protein >= 25) {
    sentences.push(render(t.protein, { protein }));
  }
  if (ctx.isTrainingDay && protein >= 35) {
    sentences.push(t.trainingDay);
  }

  if ((parts.rating ?? 0) >= 0.8 && candidate.householdRating != null) {
    sentences.push(t.householdRating);
  }

  if ((parts.holiday ?? 0) >= 1 && ctx.activeHolidayTags.length > 0) {
    sentences.push(t.holiday);
  } else if ((parts.season ?? 0) >= 1) {
    sentences.push(t.season);
  }

  if ((parts.time ?? 0) >= 1 && ctx.isWeekday) {
    sentences.push(render(t.time, { minutes: candidate.totalTimeMinutes }));
  }

  if ((parts.budget ?? 0) >= 1 && candidate.estimatedCostMinorPerPortion != null) {
    sentences.push(
      render(t.budget, { cost: Math.round(candidate.estimatedCostMinorPerPortion / 100) }),
    );
  }

  if ((parts.craving ?? 0) >= 1) {
    sentences.push(t.craving);
  }

  // S1: personaliserings-mallar från provenans
  if (ctx.personalizationEnabled && provenance.length > 0) {
    const rendered = renderProvenance(provenance.slice(0, 2), languageTag); // max 2 personliga satser
    if (rendered) {
      sentences.push(rendered);
    }
  }

  if (sentences.length === 0) {
    sentences.push(t.fallback);
  }

  return sentences.join(" ");
}

/** Bakåtkompatibel wrapper: svensk whySv. */
export function buildWhySv(
  candidate: RecommendationCandidate,
  ctx: RecommendationContext,
  parts: Record<string, number>,
  provenance: ProvenanceEntry[] = [],
): string {
  return buildWhy(candidate, ctx, parts, provenance, "sv-SE");
}

function capitalize(s: string): string {
  return s.length === 0 ? s : s[0]!.toUpperCase() + s.slice(1);
}

/** Kompakt kontextsammanfattning (utan persondata) till AAMOS RANK_RECIPES. */
export function summarizeContext(ctx: RecommendationContext): string {
  const parts = [
    `måltid=${ctx.mealType}`,
    `personer=${ctx.persons}`,
    `säsong=${ctx.currentSeason}`,
    ctx.isWeekday ? "vardag" : "helg",
  ];
  if (ctx.maxMinutes != null) parts.push(`maxMinuter=${ctx.maxMinutes}`);
  if (ctx.activeHolidayTags.length > 0) parts.push(`högtider=${ctx.activeHolidayTags.join("+")}`);
  if (ctx.cravingTags && ctx.cravingTags.length > 0)
    parts.push(`sugen_på=${ctx.cravingTags.join("+")}`);
  if (ctx.cravingCuisine) parts.push(`kök=${ctx.cravingCuisine}`);
  return parts.join(", ");
}
