/* ============================================================
   BAN YARO — App Core
   Router, State-Management, Navigation, Initialisierung.
   ============================================================ */

const APP_VER     = '660'; // ← bei jedem Deploy mit Frontend-Änderungen erhöhen
const APP_VERSION = '1.3.0'; // ← semantische Version, wird bei make release gesetzt
const IS_STAGING  = location.hostname === 'staging.banyaro.app';

const App = (() => {

  // ----------------------------------------------------------
  // PWA INSTALL PROMPT — frühzeitig abfangen, bevor es verloren geht
  // ----------------------------------------------------------
  let _installPrompt = null;
  window.addEventListener('beforeinstallprompt', e => {
    e.preventDefault();
    _installPrompt = e;
  });

  // ----------------------------------------------------------
  // STATE — zentraler App-Zustand
  // ----------------------------------------------------------
  const state = {
    user:       null,    // eingeloggter User (oder null)
    dogs:       [],      // Hunde des Users
    activeDog:  null,    // aktuell gewählter Hund
    page:       'diary', // aktive Seite
  };

  // ----------------------------------------------------------
  // SEITENDEFINITIONEN
  // Jede Seite: { id, title, load() }
  // load() wird beim ersten Aufruf einmalig ausgeführt
  // ----------------------------------------------------------
  const pages = {
    welcome:    { title: 'Willkommen',        module: null },
    onboarding: { title: 'Einrichtung',       module: null, requiresAuth: true },
    diary:      { title: 'Tagebuch',         module: null, requiresAuth: true },
    health:     { title: 'Gesundheit',       module: null, requiresAuth: true },
    'dog-profile': { title: 'Mein Hund',    module: null, requiresAuth: true },
    map:        { title: 'Karte',            module: null },
    routes:     { title: 'Routen',           module: null },
    events:     { title: 'Events',           module: null },
    poison:     { title: 'Giftköder-Alarm',  module: null },
    walks:      { title: 'Gassi-Treffen',    module: null, requiresAuth: true },
    sitting:    { title: 'Sitting',          module: null, requiresAuth: true },
    forum:      { title: 'Forum',            module: null },
    wiki:       { title: 'Wiki',             module: null },
    knigge:     { title: 'Knigge',           module: null },
    movies:     { title: 'Filme',            module: null },
    trainingsplaene: { title: 'Trainingspläne', module: null },
    uebungen:   { title: 'Übungsbibliothek', module: null },
    notes:      { title: 'Notizblock',       module: null, requiresAuth: true },
    'erste-hilfe': { title: 'Erste Hilfe',   module: null },
    settings:   { title: 'Einstellungen',    module: null },
    lost:       { title: 'Verlorener Hund',  module: null },
    friends:    { title: 'Freunde',          module: null, requiresAuth: true },
    chat:       { title: 'Nachrichten',      module: null, requiresAuth: true },
    social:     { title: 'Social Media',      module: null, requiresAuth: true },
    admin:      { title: 'Admin',            module: null, requiresAuth: true },
    moderation: { title: 'Moderation',       module: null, requiresAuth: true },
    impressum:   { title: 'Impressum',        module: null },
    datenschutz: { title: 'Datenschutz',      module: null },
    widget:         { title: 'Widget',             module: null, requiresAuth: true },
    notifications:  { title: 'Aktuelles',           module: null, requiresAuth: true },
    breeder:        { title: 'Züchter-Profil',      module: null },
    litters:        { title: 'Wurfverwaltung',       module: null, requiresAuth: true },
    wurfboerse:     { title: 'Wurfbörse',            module: null },
    zuchthunde:     { title: 'Zuchtkartei',          module: null, requiresAuth: true },
    'zucht-profil': { title: 'Hunde-Profil',         module: null },
    gruender:       { title: '100 Gründer',           module: null },
    jobs:           { title: 'Wir suchen dich',       module: null },
    expenses:       { title: 'Ausgaben',               module: null, requiresAuth: true },
    recalls:        { title: 'Rückrufe',               module: null },
    adoption:       { title: 'Adoption',               module: null },
    playdate:       { title: 'Playdate',               module: null, requiresAuth: true },
    wetter:         { title: 'Wetter',                 module: null },
  };

  // ----------------------------------------------------------
  // AUTH GUARD — Login-Gate Texte pro Seite
  // ----------------------------------------------------------
  const AUTH_GATE = {
    diary:        { icon: 'book-open',        text: 'Dein persönliches Hunde-Tagebuch — Fotos, Notizen, Stimmungen. Nur für dich, privat und sicher.', preview: '/img/screenshots/screen-1.jpg' },
    health:       { icon: 'syringe',          text: 'Impfungen, Tierarztbesuche, Gewicht und Medikamente — alles an einem Ort, immer abrufbar.', preview: '/img/screenshots/screen-3.jpg' },
    'dog-profile':{ icon: 'paw-print',        text: 'Erstelle ein Profil für deinen Hund mit Foto, Bio, Chip-Nr. und NFC-Tag.', preview: null },
    friends:      { icon: 'users',            text: 'Finde Hundebesitzer in deiner Nähe und tausche dich aus.', preview: null },
    chat:         { icon: 'chat-circle-dots', text: 'Schreibe direkt mit anderen Hundebesitzern.', preview: null },
    walks:        { icon: 'paw-print',        text: 'Organisiere Gassi-Treffen und triff andere Hunde.', preview: '/img/screenshots/screen-5.jpg' },
    sitting:      { icon: 'house-line',       text: 'Finde einen Dogsitter oder biete selbst Sitting an.', preview: null },
    uebungen:     { icon: 'target',           text: 'Über 100 Übungen mit Anleitungen — tracke deinen Trainingsfortschritt.', preview: '/img/screenshots/screen-4.jpg' },
    notes:        { icon: 'note-pencil',      text: 'Dein persönlicher Notizblock — für alles was du nicht vergessen willst.', preview: null },
    playdate:     { icon: 'paw-print',        text: 'Finde Spielkameraden für deinen Hund in der Nähe und verabrede ein Treffen.', preview: null },
  };

  // ----------------------------------------------------------
  // ROUTER
  // ----------------------------------------------------------
  function navigate(pageId, pushHistory = true, params = {}) {
    if (!pages[pageId]) return;
    if (window.Worlds?._visible) window.Worlds.hide();

    // Aktive Seite ausblenden
    document.querySelector('.page.active')?.classList.remove('active');
    document.querySelectorAll('.nav-item.active, .sidebar-item.active')
      .forEach(el => el.classList.remove('active'));

    // Neue Seite einblenden
    document.getElementById(`page-${pageId}`)?.classList.add('active');

    // Navigation markieren
    document.querySelectorAll(`[data-page="${pageId}"]`)
      .forEach(el => el.classList.add('active'));

    // Header-Titel setzen (nur wenn kein Dog-Switcher aktiv ist)
    const titleEl = document.getElementById('header-title');
    if (titleEl) titleEl.textContent = pages[pageId].title;

    // History
    if (pushHistory) {
      history.pushState({ page: pageId }, '', `#${pageId}`);
    }

    state.page = pageId;
    UI.scrollTop();

    // Seiten-Modul lazy laden (einmalig)
    _loadPage(pageId, params);
  }

  async function _loadPage(pageId, params = {}) {
    const page = pages[pageId];

    // AUTH GUARD — geschützte Seiten für nicht-eingeloggte User → Welcome
    if (page.requiresAuth && !state.user) {
      navigate('welcome', false);
      return;
    }

    if (page.module) {
      const hasParams = params && Object.keys(params).length > 0;
      if (hasParams) {
        // Re-init mit neuen Params (z.B. Chat mit bestimmter Konversation)
        const container = document.querySelector(`#page-${pageId} .page-body`);
        page.module.init?.(container, state, params);
      } else {
        page.module.refresh?.();
      }
      return;
    }

    // Guard: verhindert doppelten Load bei gleichzeitigen navigate()-Aufrufen
    if (page._loading) return;
    page._loading = true;

    const container = document.querySelector(`#page-${pageId} .page-body`);
    if (!container) { page._loading = false; return; }

    // Skeleton während Laden
    container.innerHTML = UI.skeleton(4);

    try {
      // Seiten-Script dynamisch laden
      await _loadScript(`/js/pages/${pageId}.js`);
      const mod = window[`Page_${pageId.replace(/-/g, '_')}`];
      if (mod?.init) {
        await mod.init(container, state, params);
        page.module = mod;
      } else {
        // Platzhalter wenn Seite noch nicht gebaut
        container.innerHTML = UI.emptyState({
          icon: '🚧',
          title: pages[pageId].title,
          text: 'Diese Seite ist noch in Entwicklung.',
        });
        page.module = {}; // verhindert erneutes Laden
      }
    } catch {
      container.innerHTML = UI.emptyState({
        icon: '🚧',
        title: pages[pageId].title,
        text: 'Diese Seite ist noch in Entwicklung.',
      });
      page.module = {};
    } finally {
      page._loading = false;
    }
  }

  // ----------------------------------------------------------
  // LOGIN GATE — wird statt Seiteninhalt angezeigt
  // ----------------------------------------------------------
  function _renderLoginGate(container, pageId) {
    const gate  = AUTH_GATE[pageId] || { icon: 'lock', text: 'Dieser Bereich ist nur für angemeldete Nutzer.' };
    const title = pages[pageId]?.title || 'Dieser Bereich';

    container.innerHTML = `
      <div style="display:flex;flex-direction:column;align-items:center;justify-content:center;
                  min-height:60vh;padding:var(--space-6) var(--space-5);text-align:center;gap:var(--space-4)">

        <!-- Preview-Screenshot (wenn vorhanden) -->
        ${gate.preview ? `
        <div style="position:relative;width:100%;max-width:280px;border-radius:var(--radius-lg);
                    overflow:hidden;box-shadow:0 8px 32px rgba(0,0,0,0.15)">
          <img src="${gate.preview}" alt="${UI.escape(title)}"
               style="width:100%;display:block;filter:blur(3px) brightness(0.7);transform:scale(1.05)">
          <div style="position:absolute;inset:0;display:flex;align-items:center;justify-content:center">
            <div style="background:rgba(255,255,255,0.15);backdrop-filter:blur(4px);
                        border-radius:var(--radius-md);padding:var(--space-3) var(--space-4);
                        border:1px solid rgba(255,255,255,0.3)">
              <svg style="width:28px;height:28px;color:#fff;display:block;margin:0 auto" aria-hidden="true">
                <use href="/icons/phosphor.svg#lock-simple"></use>
              </svg>
              <span style="font-size:var(--text-xs);color:#fff;font-weight:700;display:block;margin-top:4px">
                Nur für Mitglieder
              </span>
            </div>
          </div>
        </div>` : `
        <div style="width:64px;height:64px;border-radius:50%;
                    background:var(--c-primary-subtle);
                    display:flex;align-items:center;justify-content:center">
          <svg style="width:32px;height:32px;color:var(--c-primary)" aria-hidden="true">
            <use href="/icons/phosphor.svg#${UI.escape(gate.icon)}"></use>
          </svg>
        </div>`}

        <!-- Text -->
        <div style="max-width:300px">
          <h2 style="font-size:var(--text-xl);font-weight:var(--weight-bold);
                     color:var(--c-text);margin:0 0 var(--space-2)">
            ${UI.escape(title)}
          </h2>
          <p style="font-size:var(--text-sm);color:var(--c-text-secondary);
                    line-height:1.6;margin:0">
            ${UI.escape(gate.text)}
          </p>
        </div>

        <!-- CTAs -->
        <div style="display:flex;flex-direction:column;gap:var(--space-3);width:100%;max-width:280px">
          <button class="btn btn-primary" id="gate-register-btn">
            <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#user-plus"></use></svg>
            Kostenlos registrieren
          </button>
          <button class="btn btn-ghost" id="gate-login-btn" style="font-size:var(--text-sm)">
            Schon dabei? Anmelden
          </button>
        </div>

        <!-- Hinweis was sonst frei ist -->
        <p style="font-size:var(--text-xs);color:var(--c-text-muted);margin:0">
          Karte, Wiki, Übungen, Erste Hilfe und mehr sind ohne Account zugänglich.
        </p>

        <!-- Install-Hinweis -->
        <button id="gate-install-hint"
                style="background:none;border:none;cursor:pointer;padding:0;
                       font-size:var(--text-xs);color:var(--c-primary);
                       display:flex;align-items:center;gap:4px;text-decoration:underline">
          <svg style="width:13px;height:13px" aria-hidden="true">
            <use href="/icons/phosphor.svg#download-simple"></use>
          </svg>
          Ban Yaro als App installieren
        </button>

      </div>
    `;

    container.querySelector('#gate-login-btn')?.addEventListener('click', () => {
      navigate('settings');
    });
    container.querySelector('#gate-register-btn')?.addEventListener('click', () => {
      navigate('settings');
    });
    container.querySelector('#gate-install-hint')?.addEventListener('click', () => {
      navigate('welcome');
    });
  }

  function _loadScript(src) {
    // Versionierter URL damit SW/Browser-Cache bei jedem Deploy invalidiert wird
    const versioned = `${src}?v=${APP_VER}`;
    return new Promise((resolve, reject) => {
      if (document.querySelector(`script[src="${versioned}"]`)) { resolve(); return; }
      const s = document.createElement('script');
      s.src = versioned;
      s.onload  = resolve;
      s.onerror = reject;
      document.head.appendChild(s);
    });
  }

  // ----------------------------------------------------------
  // NAVIGATION EVENTS
  // ----------------------------------------------------------
  function _bindNavigation() {
    // Bottom Nav + Sidebar Klicks
    document.addEventListener('click', e => {
      const item = e.target.closest('[data-page]');
      if (item) {
        navigate(item.dataset.page);
        if (item.closest('#sidebar')) _closeSidebar();
        return;
      }

      // Header-User-Button → Settings
      if (e.target.closest('#header-user-btn')) {
        navigate('settings');
        return;
      }

      // Sidebar-Logo → Willkommensseite (oder Hund-Profil wenn Hund aktiv)
      // Hinweis: dog-sw-title hat eigenen Listener; dieser Fallback greift nur
      // wenn kein Hund aktiv ist (statischer "Ban Yaro"-Text ohne dog-sw-title).
      if (e.target.closest('.sidebar-logo-text') && !e.target.closest('.dog-sw-title')) {
        navigate('welcome');
        _closeSidebar();
        return;
      }

      // Sidebar-User (kein data-page, damit keine Aktiv-Markierung)
      if (e.target.closest('#sidebar-user')) {
        navigate('settings');
        _closeSidebar();
        return;
      }

      // + Button (Mobile Bottom-Nav + Desktop Sidebar)
      if (e.target.closest('#nav-add') || e.target.closest('#sidebar-add')) {
        _closeSidebar();
        _showQuickAdd();
        return;
      }

      // Hamburger-Menü (Mobile)
      if (e.target.closest('#header-menu-btn')) {
        _toggleSidebar();
        return;
      }

      // Backdrop → Sidebar schließen
      if (e.target.closest('#sidebar-backdrop')) {
        _closeSidebar();
        return;
      }

      // Sidebar-Item auf Mobile → schließen nach Navigation
      if (e.target.closest('#sidebar .sidebar-item')) {
        _closeSidebar();
      }
    });

    // Browser Back/Forward
    window.addEventListener('popstate', e => {
      _closeSidebar();
      const page = e.state?.page || 'diary';
      navigate(page, false);
    });

    // Hash-Navigation wird in init() nach _checkAuth() behandelt (nicht hier),
    // damit kein doppelter _loadPage()-Aufruf entsteht.
  }

  // ----------------------------------------------------------
  // MOBILE SIDEBAR DRAWER
  // ----------------------------------------------------------
  function _toggleSidebar() {
    const sidebar  = document.getElementById('sidebar');
    const backdrop = document.getElementById('sidebar-backdrop');
    const isOpen   = sidebar?.classList.contains('open');
    isOpen ? _closeSidebar() : _openSidebar();
  }

  function _openSidebar() {
    document.getElementById('sidebar')?.classList.add('open');
    document.getElementById('sidebar-backdrop')?.classList.add('visible');
  }

  function _closeSidebar() {
    document.getElementById('sidebar')?.classList.remove('open');
    document.getElementById('sidebar-backdrop')?.classList.remove('visible');
  }

  // ----------------------------------------------------------
  // SCHNELL-HINZUFÜGEN (+ Button)
  // ----------------------------------------------------------
  function _showQuickAdd() {
    const loggedIn = !!state.user;

    const authBtn = (quick, cls, icon, label) => loggedIn
      ? `<button class="btn ${cls} w-full" data-quick="${quick}">
           <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#${icon}"></use></svg> ${label}
         </button>`
      : `<button class="btn ${cls} w-full" style="opacity:0.5" data-quick="auth-${quick}">
           <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#lock"></use></svg> ${label}
         </button>`;

    UI.modal.open({
      title: 'Schnellmeldung',
      body: `
        <div class="flex flex-col gap-3">
          ${authBtn('diary', 'btn-primary',   'book-open',        'Tagebucheintrag schreiben')}
          <button class="btn btn-danger w-full" data-quick="poison">
            <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#warning-octagon"></use></svg> Giftköder melden
          </button>
          ${authBtn('walk', 'btn-secondary', 'paw-print',       'Gassi-Treffen erstellen')}
          ${authBtn('lost', 'btn-secondary', 'magnifying-glass','Verlorener Hund melden')}
        </div>
        ${!loggedIn ? `<p style="font-size:var(--text-xs);color:var(--c-text-muted);text-align:center;margin-top:var(--space-3)">
          <svg class="ph-icon" style="width:12px;height:12px" aria-hidden="true"><use href="/icons/phosphor.svg#info"></use></svg>
          Einige Funktionen erfordern einen Account.
        </p>` : ''}
      `,
    });

    // Quick-Add Aktionen
    document.querySelector('#modal-container').addEventListener('click', e => {
      const btn = e.target.closest('[data-quick]');
      if (!btn) return;
      const action = btn.dataset.quick;
      UI.modal.close();
      // Kurzes Delay wegen iOS Ghost-Click: nach modal.close() feuert iOS
      // ~300ms später ein synthetisches Click-Event an derselben Position.
      // Ohne Delay trifft es das neu geöffnete Modal und schließt es sofort.
      setTimeout(() => {
        if (action.startsWith('auth-')) { navigate('settings'); return; }
        if (action === 'diary')  { navigate('diary');  setTimeout(() => pages['diary'].module?.openNew?.(),  400); }
        if (action === 'poison') { navigate('poison'); pages['poison'].module?.openNew?.(); }
        if (action === 'walk')   { navigate('walks');  pages['walks'].module?.openNew?.(); }
        if (action === 'lost')   { navigate('lost');   setTimeout(() => pages['lost'].module?.openNew?.(), 400); }
      }, 350);
    }, { once: true });
  }

  // ----------------------------------------------------------
  // AUTH
  // ----------------------------------------------------------
  async function _checkAuth() {
    try {
      const user = await API.auth.me();
      state.user = user;
      await _onLoggedIn();
    } catch {
      _onLoggedOut();
    }
  }

  async function _onLoggedIn() {
    document.getElementById('sidebar-username').textContent = state.user.name;
    document.getElementById('header-login-btn')?.remove();
    _updateHeaderUserBtn(true);
    // Admin/Moderator-Item einblenden
    const adminItem = document.getElementById('sidebar-admin');
    if (adminItem) {
      const isMod = state.user.rolle === 'admin' || state.user.rolle === 'moderator'
                 || state.user.is_moderator;
      adminItem.style.display = isMod ? '' : 'none';
    }
    const moderationItem = document.getElementById('sidebar-moderation');
    if (moderationItem) {
      const isMod = state.user.rolle === 'admin' || state.user.rolle === 'moderator'
                 || state.user.is_moderator;
      moderationItem.style.display = isMod ? '' : 'none';
    }
    const isBreeder = state.user.rolle === 'breeder' || state.user.rolle === 'admin';
    const littersItem = document.getElementById('sidebar-litters');
    if (littersItem) littersItem.style.display = isBreeder ? '' : 'none';
    const zuchthundeItem = document.getElementById('sidebar-zuchthunde');
    if (zuchthundeItem) zuchthundeItem.style.display = isBreeder ? '' : 'none';
    const socialItem = document.getElementById('sidebar-social');
    if (socialItem) {
      const isSocial = state.user.is_social_media || state.user.rolle === 'admin';
      socialItem.style.display = isSocial ? '' : 'none';
    }
    await _loadDogs();

    // Eingeloggter User ohne Hund → Onboarding-Wizard (einmalig)
    if (state.dogs.length === 0 && !localStorage.getItem('by_onboarding_done')) {
      navigate('onboarding');
    }

    _showVerifyBanner();
    _updateNotifBadge();
    _updateChatBadge();
    _checkNearbyAlerts();
    setInterval(() => { _updateNotifBadge(); _updateChatBadge(); }, 30_000);
    setInterval(_checkNearbyAlerts, 5 * 60_000);
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible') {
        _updateNotifBadge();
        _updateChatBadge();
        _checkNearbyAlerts();
        if (state.page === 'chat') {
          pages['chat']?.module?.refresh?.();
        }
      }
    });

    const pendingInvite = sessionStorage.getItem('pending_invite');
    if (pendingInvite) {
      sessionStorage.removeItem('pending_invite');
      _handleInvite(pendingInvite);
    }
  }

  async function _checkNearbyAlerts() {
    const nav = document.getElementById('bottom-nav');
    if (!nav) return;
    try {
      const pos = await new Promise((resolve, reject) =>
        navigator.geolocation.getCurrentPosition(resolve, reject, { timeout: 5000, maximumAge: 120_000 })
      );
      const { latitude: lat, longitude: lon } = pos.coords;
      const data = await API.get(`/alerts?lat=${lat}&lon=${lon}`);
      nav.classList.toggle('alert-poison', !!data.poison);
      nav.classList.toggle('alert-lost',   !data.poison && !!data.lost);
      // Burger-Badge: Giftköder/Verlorener Hund in der Nähe
      document.getElementById('notif-nav-badge')?.classList.toggle('hidden', !data.poison && !data.lost);
    } catch {
      // Kein Standort verfügbar — kein Alert anzeigen
    }
  }

  async function _updateNotifBadge() {
    if (!state.user) return;
    try {
      const b = await API.notifications.badge();
      document.getElementById('chat-nav-badge')?.classList.toggle('hidden', !b.personal);
    } catch { /* ignorieren */ }
  }

  async function _updateChatBadge() {
    if (!state.user) return;
    try {
      const convs = await API.chat.conversations();
      const total = convs.reduce((s, c) => s + (c.unread_count || 0), 0);
      const badge = document.getElementById('chat-badge');
      if (badge) { badge.textContent = total; badge.style.display = total > 0 ? '' : 'none'; }
    } catch { /* ignorieren */ }
  }

  function _onLoggedOut() {
    state.user      = null;
    state.dogs      = [];
    state.activeDog = null;

    // Gecachte Module geschützter Seiten leeren, damit sie beim nächsten Login
    // sauber neu initialisiert werden statt den alten Zustand zu refreshen.
    Object.entries(pages).forEach(([, page]) => {
      if (page.requiresAuth) page.module = null;
    });

    _renderDogSwitcher();

    _updateHeaderUserBtn(false);

    // Nicht eingeloggte User immer zur Welcome-Seite
    navigate('welcome', false);
  }

  function _showVerifyBanner() {
    const banner = document.getElementById('verify-banner');
    if (!banner) return;
    if (!state.user || state.user.email_verified) {
      banner.style.display = 'none';
      return;
    }
    const dismissed = sessionStorage.getItem('by_verify_dismissed');
    if (dismissed) return;
    banner.style.display = 'flex';

    document.getElementById('verify-resend-btn')?.addEventListener('click', async () => {
      await API.post('/auth/resend-verification', { email: state.user.email });
      UI.toast.success('Bestätigungs-Mail erneut gesendet.');
    }, { once: true });

    document.getElementById('verify-banner-close')?.addEventListener('click', () => {
      banner.style.display = 'none';
      sessionStorage.setItem('by_verify_dismissed', '1');
    }, { once: true });
  }

  function _updateHeaderUserBtn(loggedIn) {
    const btn  = document.getElementById('header-user-btn');
    const icon = document.getElementById('header-user-icon');
    if (!btn) return;
    if (loggedIn) {
      const av = state.user?.avatar_url;
      if (av) {
        btn.innerHTML = `<img src="${av}" style="width:100%;height:100%;object-fit:cover;border-radius:50%">`;
      } else {
        btn.innerHTML = `<svg class="ph-icon" aria-hidden="true" style="width:18px;height:18px;color:var(--c-primary)">
          <use href="/icons/phosphor.svg#user"></use></svg>`;
      }
      btn.style.borderColor = 'var(--c-primary)';
      btn.title = 'Mein Profil';
    } else {
      btn.innerHTML = `<svg class="ph-icon" aria-hidden="true" style="width:18px;height:18px;color:var(--c-text-muted)">
        <use href="/icons/phosphor.svg#user"></use></svg>
        <div style="position:absolute;bottom:0;right:0;width:10px;height:10px;border-radius:50%;
                    background:var(--c-danger);border:2px solid var(--c-surface)"></div>`;
      btn.style.borderColor = 'var(--c-border)';
      btn.title = 'Anmelden';
    }
  }

  async function _loadDogs() {
    try {
      state.dogs = await API.dogs.list();
      if (state.dogs.length > 0) {
        // Zuletzt aktiven Hund aus localStorage wiederherstellen
        const savedId = parseInt(localStorage.getItem('by_active_dog') || '0');
        state.activeDog = state.dogs.find(d => d.id === savedId) || state.dogs[0];
      }
      _renderDogSwitcher();
      _notifyDogChange();
    } catch { /* kein Hund vorhanden */ }
  }

  // ----------------------------------------------------------
  // ONBOARDING — Willkommens-Modal für neue User
  // ----------------------------------------------------------
  function _showOnboardingModal() {
    UI.modal.open({
      title: `${UI.icon('paw-print')} Willkommen bei Ban Yaro!`,
      body: `
        <div style="display:flex;flex-direction:column;align-items:center;
                    gap:var(--space-4);text-align:center;padding:var(--space-2) 0">
          <div style="width:64px;height:64px;border-radius:50%;
                      background:var(--c-primary-subtle);
                      display:flex;align-items:center;justify-content:center">
            <svg style="width:32px;height:32px;color:var(--c-primary)" aria-hidden="true">
              <use href="/icons/phosphor.svg#dog"></use>
            </svg>
          </div>
          <div style="max-width:300px">
            <p style="margin:0 0 var(--space-3);font-size:var(--text-sm);
                      color:var(--c-text-secondary);line-height:1.6">
              Schön, dass du dabei bist! Ban Yaro hilft dir, alles rund um
              deinen Hund im Blick zu behalten — Spaziergänge, Gesundheit,
              Termine und vieles mehr.
            </p>
            <p style="margin:0;font-size:var(--text-sm);
                      color:var(--c-text-secondary);line-height:1.6">
              Fang jetzt an und leg ein Profil für deinen Hund an.
            </p>
          </div>
        </div>
      `,
      footer: `
        <button type="button" class="btn btn-primary" id="onboarding-start-btn">
          ${UI.icon('dog')} Meinen ersten Hund anlegen
        </button>
        <button type="button" class="btn btn-ghost" data-modal-close>Später</button>
      `,
    });

    document.getElementById('onboarding-start-btn')?.addEventListener('click', () => {
      UI.modal.close();
      navigate('dog-profile');
    });
  }

  function _notifyDogChange() {
    Object.values(pages).forEach(p => p.module?.onDogChange?.(state.activeDog));
  }

  // ----------------------------------------------------------
  // HUNDE-SWITCHER (Header Mobile + Sidebar-Logo Desktop)
  // ----------------------------------------------------------
  function _renderDogSwitcher() {
    _renderSwitcherInto(document.getElementById('header-dog-switcher'), 'hdr');
    _renderSwitcherInto(document.getElementById('sidebar-dog-switcher'), 'sb');
  }

  function _renderSwitcherInto(el, ctxId) {
    if (!el) return;

    const dog    = state.activeDog;
    const others = state.dogs.filter(d => d.id !== dog?.id);

    // Fallback: kein User oder kein Hund → Standardlogo
    if (!state.user || !dog) {
      if (ctxId === 'sb') {
        el.innerHTML = `
          <img class="sidebar-logo-img" src="/icons/icon-180.png" alt="Ban Yaro">
          <span class="sidebar-logo-text">Ban Yaro</span>`;
      } else {
        el.innerHTML = `<span class="header-title" id="header-title">Ban Yaro</span>`;
      }
      return;
    }

    const avHtml = d => d.foto_url
      ? `<img src="${UI.escape(d.foto_url)}" alt="${UI.escape(d.name)}"
             style="transform:scale(${d.foto_zoom||1}) translate(${d.foto_offset_x||0}%,${d.foto_offset_y||0}%)">`
      : `<span>🐕</span>`;

    // Inaktive Hunde rechts
    let othersHtml = '';
    if (others.length === 1) {
      othersHtml = `
        <div class="dog-sw-others">
          <div class="dog-sw-other" data-dog-id="${others[0].id}" title="${UI.escape(others[0].name)}">
            ${avHtml(others[0])}
          </div>
        </div>`;
    } else if (others.length >= 2) {
      const visible    = others.slice(0, 3);
      const extraCount = others.length - 3;
      othersHtml = `
        <div class="dog-sw-others">
          <div class="dog-sw-stack" id="dog-sw-stack-${ctxId}">
            ${visible.map((d, i) => `
              <div class="dog-sw-other dog-sw-other--${i}" data-dog-id="${d.id}" title="${UI.escape(d.name)}">
                ${avHtml(d)}
              </div>`).join('')}
            ${extraCount > 0 ? `<div class="dog-sw-more">+${extraCount}</div>` : ''}
          </div>
          <div class="dog-quickpick hidden" id="dog-qp-${ctxId}">
            ${others.map(d => `
              <div class="dog-qp-item" data-dog-id="${d.id}">
                <div class="dog-qp-av">${avHtml(d)}</div>
                <span>${UI.escape(d.name)}</span>
              </div>`).join('')}
          </div>
        </div>`;
    }

    const titleClass = ctxId === 'sb' ? 'sidebar-logo-text' : 'header-title';
    el.innerHTML = `
      <div class="dog-sw-active" id="dog-sw-active-${ctxId}" title="${UI.escape(dog.name)} bearbeiten"
           style="position:relative">
        ${avHtml(dog)}
        ${dog.is_guest ? `<span style="position:absolute;bottom:-2px;right:-2px;
            background:var(--c-primary);color:#fff;border-radius:var(--radius-full);
            font-size:8px;font-weight:700;padding:1px 4px;line-height:1.4;
            border:1px solid var(--c-surface)">GAST</span>` : ''}
      </div>
      <span class="${titleClass} dog-sw-title" style="cursor:pointer" title="${UI.escape(dog.name)} bearbeiten">${UI.escape(dog.name)}</span>
      ${othersHtml}`;

    // Klick aktiver Avatar → Welcome-Seite; Klick Name → Hund-Profil
    el.querySelector(`#dog-sw-active-${ctxId}`)?.addEventListener('click', () => {
      navigate('welcome');
    });
    el.querySelector(`.dog-sw-title`)?.addEventListener('click', () => {
      navigate('dog-profile');
      if (ctxId === 'sb') _closeSidebar();
    });

    // 1 anderer Hund → direkter Tausch
    if (others.length === 1) {
      el.querySelector('.dog-sw-other')?.addEventListener('click', () => {
        setActiveDog(others[0].id);
      });
    }

    // 2+ andere Hunde → Stack klick öffnet Quickpicker
    if (others.length >= 2) {
      const stack = el.querySelector(`#dog-sw-stack-${ctxId}`);
      const qp    = el.querySelector(`#dog-qp-${ctxId}`);
      stack?.addEventListener('click', e => {
        e.stopPropagation();
        // Alle anderen Quickpicker schließen
        document.querySelectorAll('.dog-quickpick').forEach(q => {
          if (q !== qp) q.classList.add('hidden');
        });
        qp?.classList.toggle('hidden');
      });
      el.querySelectorAll('.dog-qp-item').forEach(item => {
        item.addEventListener('click', e => {
          e.stopPropagation();
          setActiveDog(parseInt(item.dataset.dogId));
          qp?.classList.add('hidden');
        });
      });
    }
  }

  // Quickpicker schließen bei Klick außerhalb
  document.addEventListener('click', () => {
    document.querySelectorAll('.dog-quickpick').forEach(q => q.classList.add('hidden'));
  });

  function setActiveDog(dogId) {
    const dog = state.dogs.find(d => d.id === dogId);
    if (!dog || dog.id === state.activeDog?.id) return;
    state.activeDog = dog;
    localStorage.setItem('by_active_dog', String(dogId));
    _renderDogSwitcher();
    _notifyDogChange();
  }

  // ----------------------------------------------------------
  // INITIALISIERUNG
  // ----------------------------------------------------------
  async function init() {
    // Referral-Code aus URL ?ref=CODE speichern
    const urlParams = new URLSearchParams(window.location.search);
    const refCode = urlParams.get('ref');
    if (refCode) {
      sessionStorage.setItem('by_ref_code', refCode.toUpperCase());
      // URL bereinigen ohne Reload
      history.replaceState({}, '', window.location.pathname + window.location.hash);
    }

    _bindNavigation();

    try { localStorage.removeItem('by_wissen_open'); } catch (_) {}

    await _checkAuth();

    // Einladungslink /teilen/{token} → direkt annehmen
    const inviteMatch = location.pathname.match(/^\/teilen\/([A-Za-z0-9_-]+)$/);
    if (inviteMatch) {
      const token = inviteMatch[1];
      navigate('diary', false);
      _handleInvite(token);
      return;
    }

    // Erste Seite laden: Hash aus URL oder Standard 'diary'.
    const rawHash = location.hash.replace('#', '');
    const [hashPage, hashQuery] = rawHash.split('?');
    const hashParams = {};
    if (hashQuery) {
      new URLSearchParams(hashQuery).forEach((v, k) => {
        hashParams[k] = isNaN(v) ? v : Number(v);
      });
    }

    // Passwort-Reset: #reset-password?token=xxx
    if (hashPage === 'reset-password' && hashParams.token) {
      sessionStorage.setItem('by_reset_token', hashParams.token);
      history.replaceState(null, '', '/');
      navigate('settings', false);
      return;
    }

    // E-Mail-Verifikation: Redirect von /api/auth/verify-email/{token}
    if (hashParams.verified === '1' || hashParams.verified === 1) {
      if (state.user) state.user.email_verified = 1;
      document.getElementById('verify-banner')?.style?.setProperty('display', 'none');
      UI.toast.success('E-Mail-Adresse erfolgreich bestätigt!');
      history.replaceState(null, '', '/');
    } else if (hashParams.verified === 'error') {
      UI.toast.error('Ungültiger oder abgelaufener Bestätigungs-Link.');
      history.replaceState(null, '', '/');
    }

    const startPage = (hashPage && pages[hashPage]) ? hashPage : 'welcome';
    // Nicht eingeloggte User immer zur Welcome-Seite — auch bei direktem Link auf Forum, Map etc.
    navigate(state.user ? startPage : 'welcome', false, hashParams);

    // Drei Welten nach initialer Navigation starten (damit hide() in navigate() sie nicht gleich killt)
    if (window.Worlds) window.Worlds.init(state);
  }

  async function _handleInvite(token) {
    try {
      const info = await API.sharing.info(token);
      if (info.accepted_at) {
        UI.toast.success(`Du hast bereits Zugriff auf ${info.dog_name}.`);
        history.replaceState(null, '', '/');
        return;
      }

      if (!state.user) {
        sessionStorage.setItem('pending_invite', token);
        history.replaceState(null, '', '/');
        navigate('settings', false);
        UI.toast.info('Bitte melde dich an, um die Einladung anzunehmen.');
        return;
      }

      const ok = await UI.modal.confirm({
        message: `<strong>${UI.escape(info.owner_name)}</strong> möchte das Profil von
                  <strong>${UI.escape(info.dog_name)}</strong> mit dir teilen
                  (${info.role === 'editor' ? 'Lesen & Schreiben' : 'Nur lesen'}).
                  Möchtest du die Einladung annehmen?`,
      });
      if (!ok) { history.replaceState(null, '', '/'); return; }
      await API.sharing.accept(token);
      state.dogs = await API.dogs.list();
      const newDog = state.dogs.find(d => d.name === info.dog_name);
      if (newDog) {
        state.activeDog = newDog;
        localStorage.setItem('by_active_dog', String(newDog.id));
        _renderDogSwitcher();
      }
      history.replaceState(null, '', '/');
      UI.toast.success(`${UI.escape(info.dog_name)} wurde deiner Liste hinzugefügt!`);
    } catch (e) {
      UI.toast.error(e.message || 'Einladungslink ungültig.');
      history.replaceState(null, '', '/');
    }
  }

  // ----------------------------------------------------------
  // AUTH-GATE HELPER — einheitlicher "Bitte anmelden"-Block
  // ----------------------------------------------------------
  function requireAuth(container, { icon = 'user', text = 'Melde dich an, um diese Funktion zu nutzen.' } = {}) {
    container.innerHTML = UI.emptyState({
      icon:   UI.icon(icon),
      title:  'Anmelden erforderlich',
      text,
      action: `<button class="btn btn-primary" onclick="App.navigate('settings')">Anmelden</button>`,
    });
  }

  // ----------------------------------------------------------
  // ÖFFENTLICHE API
  // (andere Module können App.state, App.navigate etc. nutzen)
  // ----------------------------------------------------------
  function callModule(pageId, method, ...args) {
    navigate(pageId);
    setTimeout(() => pages[pageId]?.module?.[method]?.(...args), 500);
  }

  return { init, navigate, callModule, state, setActiveDog,
           renderDogSwitcher: _renderDogSwitcher,
           getInstallPrompt: () => _installPrompt, requireAuth,
           showOnboarding: _showOnboardingModal,
           updateNotifBadge: _updateNotifBadge,
           checkNearbyAlerts: _checkNearbyAlerts,
           loadScript: _loadScript };

})();

window.App = App; // Worlds kann App.navigate() aufrufen

// App starten
document.addEventListener('DOMContentLoaded', () => {
  App.init();
  if (IS_STAGING) {
    document.title = '⚗️ ' + document.title;
    // Nach App.init() Styles direkt setzen — sonst überschreibt init sie
    const _applyStaging = () => {
      const nav = document.getElementById('bottom-nav');
      if (!nav) return;
      nav.style.cssText += ';background:#2d1b69!important;border-top-color:#7c3aed!important;box-shadow:0 -2px 12px rgba(124,58,237,0.4)!important';
      nav.querySelectorAll('.nav-item-label').forEach(el => el.style.color = 'rgba(196,181,253,0.75)');
      nav.querySelectorAll('.plus-btn, .nav-item-center button').forEach(el => el.style.background = '#7c3aed');
    };
    _applyStaging();
    setTimeout(_applyStaging, 400); // nochmal nach vollständigem Render
  }
});
