const translations = {
  en: {
    "lang.label": "Language",
    "lang.en": "English",
    "lang.de": "Deutsch",

    "auth.loginTab": "Log in",
    "auth.registerTab": "Register",
    "auth.username": "Username",
    "auth.password": "Password",
    "auth.displayName": "Display name (shows to group)",
    "auth.adminKey": "Admin key (optional)",
    "auth.loginSubmit": "Log in",
    "auth.registerSubmit": "Create account",
    "auth.loginHeading": "Log in",
    "auth.registerHeading": "Create account",
    "auth.switchToRegister": "Need an account? Register",
    "auth.switchToLogin": "Have an account? Log in",
    "auth.logout": "Logout",
    "auth.welcome": "Welcome, {name}!",
    "auth.defaultName": "Player",
    "auth.loading": "Loading…",
    "auth.needCredentials": "Username and password required",
    "auth.invalidCredentials": "Invalid username or password",

    "phase.suggest": "Suggest",
    "phase.reveal": "Reveal",
    "phase.vote": "Vote",
    "phase.results": "Results",
    "phase.loading": "Loading…",

    "counts.format": "Players: {players} • Suggestions: {suggestions} • Votes: {votes}",

    "nav.prev": "Back",
    "nav.next": "Next",
    "nav.waitingForResults": "Waiting…",
    "nav.freezeTitle": "Ready to reveal?",
    "nav.freezeHint": "Moving forward will freeze your suggestions. Game names become locked; only extra details stay editable.",
    "nav.freezeModalTitle": "Freeze suggestions?",
    "nav.freezeModalBody": "Once you leave Suggest, your games are locked: game names cannot be changed or deleted. Only optional details (description, links, players, artwork) remain editable. Continue?",
    "nav.voteHint": "Cast votes for every game to unlock results.",
    "nav.voteFinalized": "✅ You finalized your votes. Sit back and relax while the other players finalize their votes.",

    "suggest.title": "Suggest games (up to 5)",
    "suggest.new": "Add new suggestion",
    "suggest.addButton": "Suggest a game",
    "suggest.jokerAddButton": "🃏 Joker: add another game",
    "suggest.hint": "Only you can see your suggestions until voting starts.",
    "form.gameName": "Game name *",
    "form.genre": "Genre",
    "form.description": "Description",
    "form.players": "Players",
    "form.min": "Min",
    "form.max": "Max",
    "form.screenshot": "Screenshot URL",
    "form.youtube": "YouTube URL",
    "form.gameUrl": "Game website URL",
    "form.submit": "Submit",
    "form.placeholder.description": "Short description",
    "form.placeholder.gameName": "Game name *",
    "form.placeholder.genre": "Genre",
    "form.placeholder.screenshot": "Screenshot URL",
    "form.placeholder.youtube": "YouTube URL",
    "form.placeholder.gameUrl": "Game website URL",

    "section.mySuggestions": "Your suggestions",
    "section.allSuggestions": "All suggestions",
    "section.allSuggestions.count": "All {count} suggestions",
    "section.vote": "Vote 0-10",
    "section.vote.count": "Vote for all {count} games",
    "section.results": "Results",

    "card.edit": "Edit",
    "card.delete": "Delete",
    "card.players": "Players: {min}–{max}",
    "card.site": "Site&nbsp;↗",
    "card.youtube": "YouTube&nbsp;↗",
    "card.openScreenshot": "Open screenshot",
    "card.linked": "Votes linked",
    "card.linkedWith": "Linked with: {names}",

    "vote.saved": "Saved vote",
    "vote.missing": "Missing",
    "vote.missingWarn": "You haven’t voted yet.",
    "vote.missingFinalWarn": "You didn't vote for this game.",
    "vote.missingFooter": "At least one game is missing a score. Check before finalizing.",
    "vote.finalize": "Finalize votes",
    "vote.unfinalize": "Edit votes",
    "vote.finalHint": "Finalize when you’re done. You can unfinalize to change scores.",
    "vote.waitAdmin": "Waiting for admin to unlock results.",

    "results.rank": "Rank",
    "results.game": "Game",
    "results.author": "Author",
    "results.average": "Ø",
    "results.votesList": "All votes",
    "results.myVote": "Your vote",
    "results.links": "Links",
    "results.link.site": "Site&nbsp;↗",
    "results.link.youtube": "YouTube&nbsp;↗",

    "admin.title": "Admin",
    "admin.tools": "Admin tools",
    "admin.resultsOpenToggle": "Allow results phase",
    "admin.resultsLocked": "Results locked by admin",
    "admin.resultsUpdated": "Results availability updated",
    "admin.reset": "Reset (keep players)",
    "admin.factoryReset": "Factory reset",
    "admin.resetDone": "Reset complete",
    "admin.factoryResetDone": "Factory reset complete",
    "admin.readyForResults": "Ready for results",
    "admin.waitingForPlayers": "Waiting for players: {names}",
    "admin.playerName": "Name",
    "admin.playerUsername": "Username",
    "admin.playerStatus": "Status",
    "admin.playerGames": "Games",
    "admin.playerJoker": "Joker",
    "admin.playerDelete": "Delete",
    "admin.grantJokerChip": "Grant",
    "admin.statusSuggesting": "Suggesting",
    "admin.statusVoting": "Voting",
    "admin.statusFinished": "Finished",
    "admin.deleteTitle": "Delete account?",
    "admin.deleteBody": "Delete player \"{name}\" and all their games and votes? This cannot be undone.",
    "admin.deleteConfirm": "Delete",
    "admin.deleteDone": "Player deleted",
    "admin.jokerGranted": "Joker granted",
    "admin.linkTitle": "Link games",
    "admin.linkSource": "Game to link",
    "admin.linkTarget": "Link to (parent)",
    "admin.linkAction": "Link & clear votes",
    "admin.linkSourcePlaceholder": "Select source",
    "admin.linkTargetPlaceholder": "Select target",
    "admin.linkValidation": "Choose two different games to link.",
    "admin.linkDone": "Games linked. Votes cleared.",
    "admin.unlinkTitle": "Remove links?",
    "admin.unlinkBody": "Remove all links involving \"{name}\"? This clears votes and unfinalizes voters in this group: {peers}.",
    "admin.unlinkConfirm": "Remove links",
    "admin.unlinkDone": "Links removed. Votes cleared.",
    "admin.unlinkUnknownPeers": "linked games",

    "toast.unexpected": "Unexpected error",
    "toast.registered": "Registered",
    "toast.loggedIn": "Logged in",
    "toast.suggestionAdded": "Suggestion added",
    "toast.suggestionDeleted": "Suggestion deleted",
    "toast.savedChanges": "Saved changes",
    "toast.nameRequired": "Name required",
    "toast.displayNameRequired": "Display name is required",
    "toast.invalidImageUrl": "Screenshot URL must be http(s) and end with an image file.",

    "modal.editTitle": "Edit game",
    "modal.addTitle": "Suggest a game",
    "modal.confirmDeleteTitle": "Are you sure?",
    "modal.confirmDelete": "Confirm delete",
    "modal.save": "Save changes",
    "modal.cancel": "Cancel",
    "modal.close": "Close",

    "lightbox.close": "Close",
  },
  de: {
    "lang.label": "Sprache",
    "lang.en": "Englisch",
    "lang.de": "Deutsch",

    "auth.loginTab": "Anmelden",
    "auth.registerTab": "Registrieren",
    "auth.username": "Benutzername",
    "auth.password": "Passwort",
    "auth.displayName": "Anzeigename (für die Gruppe sichtbar)",
    "auth.adminKey": "Admin-Schlüssel (optional)",
    "auth.loginSubmit": "Anmelden",
    "auth.registerSubmit": "Konto erstellen",
    "auth.loginHeading": "Anmelden",
    "auth.registerHeading": "Konto erstellen",
    "auth.switchToRegister": "Noch kein Konto? Registrieren",
    "auth.switchToLogin": "Schon ein Konto? Anmelden",
    "auth.logout": "Abmelden",
    "auth.welcome": "Willkommen, {name}!",
    "auth.defaultName": "Spieler",
    "auth.loading": "Lädt…",
    "auth.needCredentials": "Benutzername und Passwort erforderlich",
    "auth.invalidCredentials": "Ungültiger Benutzername oder Passwort",

    "phase.suggest": "Vorschlagen",
    "phase.reveal": "Enthüllen",
    "phase.vote": "Bewerten",
    "phase.results": "Ergebnisse",
    "phase.loading": "Lädt…",

    "counts.format": "Spieler: {players} • Vorschläge: {suggestions} • Stimmen: {votes}",

    "nav.prev": "Zurück",
    "nav.next": "Weiter",
    "nav.waitingForResults": "Warten…",
    "nav.freezeTitle": "Bereit zum Aufdecken?",
    "nav.freezeHint": "Beim Weitergehen werden deine Vorschläge eingefroren. Spielnamen werden gesperrt; nur Zusatzinfos bleiben bearbeitbar.",
    "nav.freezeModalTitle": "Vorschläge einfrieren?",
    "nav.freezeModalBody": "Sobald du die Vorschlagsphase verlässt, sind deine Spiele gesperrt: Die Namen von deinen Spielen können nicht mehr geändert oder gelöscht werden. Nur optionale Angaben (Beschreibung, Links, Spielerzahlen, Bilder) bleiben bearbeitbar. Fortfahren?",
    "nav.voteHint": "Bewerte alle Spiele, um die Ergebnisse freizuschalten.",
    "nav.voteFinalized": "✅ Du hast deine Abstimmung abgeschlossen. Lehn dich zurück, bis die anderen fertig sind.",

    "suggest.title": "Schlage Spiele vor (bis zu 5)",
    "suggest.new": "Neuen Vorschlag hinzufügen",
    "suggest.addButton": "Spiel vorschlagen",
    "suggest.jokerAddButton": "🃏 Joker: Weiteres Spiel hinzufügen",
    "suggest.hint": "Nur du siehst deine Vorschläge bis zum Start der Abstimmung.",
    "form.gameName": "Spielname *",
    "form.genre": "Genre",
    "form.description": "Beschreibung",
    "form.players": "Spieler",
    "form.min": "Min",
    "form.max": "Max",
    "form.screenshot": "Screenshot-URL",
    "form.youtube": "YouTube-URL",
    "form.gameUrl": "Spiel-Webseite",
    "form.submit": "Absenden",
    "form.placeholder.description": "Kurze Beschreibung",
    "form.placeholder.gameName": "Spielname *",
    "form.placeholder.genre": "Genre",
    "form.placeholder.screenshot": "Screenshot-URL",
    "form.placeholder.youtube": "YouTube-URL",
    "form.placeholder.gameUrl": "Spiel-Webseite",

    "section.mySuggestions": "Deine Vorschläge",
    "section.allSuggestions": "Alle Vorschläge",
    "section.allSuggestions.count": "Alle {count} Vorschläge",
    "section.vote": "Bewerten 0-10",
    "section.vote.count": "Bewerte alle {count} Spiele",
    "section.results": "Ergebnisse",

    "card.edit": "Bearbeiten",
    "card.delete": "Löschen",
    "card.players": "Spieler: {min}–{max}",
    "card.site": "Webseite&nbsp;↗",
    "card.youtube": "YouTube&nbsp;↗",
    "card.openScreenshot": "Screenshot öffnen",
    "card.linked": "Verknüpfte Stimmen",
    "card.linkedWith": "Verknüpft mit: {names}",

    "vote.saved": "Stimme gespeichert",
    "vote.missing": "Fehlt",
    "vote.missingWarn": "Du hast hier noch nicht abgestimmt.",
    "vote.missingFinalWarn": "Du hast für dieses Spiel nicht abgestimmt.",
    "vote.missingFooter": "Für mindestens einen Spiel fehlt noch eine Wertung. Prüfe vor dem Abschließen.",
    "vote.finalize": "Abstimmung abschließen",
    "vote.unfinalize": "Abstimmung bearbeiten",
    "vote.finalHint": "Schließe ab, wenn du fertig bist. Zum Ändern wieder öffnen.",
    "vote.waitAdmin": "Warten, bis der Admin die Ergebnisse freigibt.",

    "results.rank": "Rang",
    "results.game": "Spiel",
    "results.author": "Autor",
    "results.average": "Ø",
    "results.votesList": "Alle Stimmen",
    "results.myVote": "Deine Stimme",
    "results.links": "Links",
    "results.link.site": "Webseite&nbsp;↗",
    "results.link.youtube": "YouTube&nbsp;↗",

    "admin.title": "Admin",
    "admin.tools": "Admin-Werkzeuge",
    "admin.resultsOpenToggle": "Ergebnisse freigeben",
    "admin.resultsLocked": "Ergebnisse vom Admin gesperrt",
    "admin.resultsUpdated": "Ergebnisfreigabe aktualisiert",
    "admin.reset": "Zurücksetzen (Spieler behalten)",
    "admin.factoryReset": "Werkseinstellung",
    "admin.resetDone": "Zurücksetzen abgeschlossen",
    "admin.factoryResetDone": "Werkseinstellung abgeschlossen",
    "admin.readyForResults": "Bereit für Ergebnisse",
    "admin.waitingForPlayers": "Warten auf: {names}",
    "admin.playerName": "Name",
    "admin.playerUsername": "Benutzername",
    "admin.playerStatus": "Status",
    "admin.playerGames": "Spiele",
    "admin.playerJoker": "Joker",
    "admin.playerDelete": "Löschen",
    "admin.grantJokerChip": "Joker",
    "admin.statusSuggesting": "Vorschlagen",
    "admin.statusVoting": "Bewerten",
    "admin.statusFinished": "Fertig",
    "admin.deleteTitle": "Konto löschen?",
    "admin.deleteBody": "Spieler \"{name}\" samt Spielen und Stimmen löschen? Dies kann nicht rückgängig gemacht werden.",
    "admin.deleteConfirm": "Löschen",
    "admin.deleteDone": "Spieler gelöscht",
    "admin.jokerGranted": "Joker vergeben",
    "admin.linkTitle": "Spiele verknüpfen",
    "admin.linkSource": "Spiel verknüpfen",
    "admin.linkTarget": "Verknüpfen mit",
    "admin.linkAction": "Verknüpfen & Stimmen löschen",
    "admin.linkSourcePlaceholder": "Quelle wählen",
    "admin.linkTargetPlaceholder": "Ziel wählen",
    "admin.linkValidation": "Wähle zwei verschiedene Spiele aus.",
    "admin.linkDone": "Spiele verknüpft. Stimmen gelöscht.",
    "admin.unlinkTitle": "Links entfernen?",
    "admin.unlinkBody": "Alle Links zu \"{name}\" entfernen? Dadurch werden Stimmen gelöscht und Finalisierungen aufgehoben für: {peers}.",
    "admin.unlinkConfirm": "Links entfernen",
    "admin.unlinkDone": "Links entfernt. Stimmen gelöscht.",
    "admin.unlinkUnknownPeers": "verknüpfte Spiele",

    "toast.unexpected": "Unerwarteter Fehler",
    "toast.registered": "Registriert",
    "toast.loggedIn": "Angemeldet",
    "toast.suggestionAdded": "Vorschlag hinzugefügt",
    "toast.suggestionDeleted": "Vorschlag gelöscht",
    "toast.savedChanges": "Änderungen gespeichert",
    "toast.nameRequired": "Name erforderlich",
    "toast.displayNameRequired": "Anzeigename ist erforderlich",
    "toast.invalidImageUrl": "Screenshot-URL muss mit http(s) beginnen und auf eine Bilddatei enden.",

    "modal.editTitle": "Spiel bearbeiten",
    "modal.addTitle": "Spiel vorschlagen",
    "modal.confirmDeleteTitle": "Bist du sicher?",
    "modal.confirmDelete": "Löschen bestätigen",
    "modal.save": "Änderungen speichern",
    "modal.cancel": "Abbrechen",
    "modal.close": "Schließen",

    "lightbox.close": "Schließen",
  }
};

const storageKey = "app_lang";
const defaultLang = "en";
let currentLang = defaultLang;
const listeners = [];

function interpolate(template, params = {}) {
  return template.replace(/\{(\w+)\}/g, (_, key) => (params[key] ?? `{${key}}`));
}

function t(key, params) {
  const fallback = translations[defaultLang][key] ?? key;
  const phrase = translations[currentLang]?.[key] ?? fallback;
  return interpolate(phrase, params);
}

function detectLanguage() {
  const stored = localStorage.getItem(storageKey);
  if (stored && translations[stored]) return stored;
  const nav = navigator.language?.slice(0, 2);
  if (nav && translations[nav]) return nav;
  return defaultLang;
}

function applyTranslations(root = document) {
  root.querySelectorAll("[data-i18n]").forEach((el) => {
    const key = el.dataset.i18n;
    const attrs = (el.dataset.i18nAttr || "")
      .split(",")
      .map((a) => a.trim())
      .filter(Boolean);
    const text = t(key);
    if (attrs.length === 0) {
      el.textContent = text;
    } else {
      attrs.forEach((attr) => el.setAttribute(attr, text));
    }
  });
}

function notify() {
  listeners.forEach((fn) => fn(currentLang));
}

function setLanguage(lang) {
  if (!translations[lang]) lang = defaultLang;
  currentLang = lang;
  localStorage.setItem(storageKey, lang);
  document.documentElement.lang = lang;
  applyTranslations();
  notify();
}

function getLanguage() {
  return currentLang;
}

function initI18n() {
  currentLang = detectLanguage();
  document.documentElement.lang = currentLang;
  applyTranslations();
  notify();
  return currentLang;
}

function onLanguageChange(fn) {
  listeners.push(fn);
}

export { t, setLanguage, getLanguage, initI18n, applyTranslations, onLanguageChange, translations };
