/* ============================================================
   BAN YARO — Gassi-Treffen
   Treffen entdecken, erstellen, beitreten
   ============================================================ */

window.Page_walks = (() => {

  let _container     = null;
  let _appState      = null;
  let _data          = [];
  let _view          = 'liste';     // 'liste' | 'karte'
  let _map           = null;
  let _markers       = [];
  let _userPos       = null;

  // _esc ersetzt durch UI.escape()

  // Datum deutsch formatieren: "2026-04-20" → "Sonntag, 20. April 2026"
  // Hinweis: UI.time.format() liefert kein weekday — daher lokale Funktion beibehalten
  function _fmtDate(iso) {
    if (!iso) return '—';
    const d = new Date(iso + 'T12:00:00');
    return d.toLocaleDateString('de-DE', { weekday: 'long', day: 'numeric', month: 'long', year: 'numeric' });
  }

  // Datum kurz: "So, 20.04." — UI.time.formatShort() gibt "20. Apr." ohne Wochentag
  // Hinweis: Format nicht äquivalent zu UI.time.formatShort() — daher lokal beibehalten
  function _fmtDateShort(iso) {
    if (!iso) return '—';
    const d = new Date(iso + 'T12:00:00');
    return d.toLocaleDateString('de-DE', { weekday: 'short', day: '2-digit', month: '2-digit' });
  }

  function _isToday(iso) {
    return iso === new Date().toISOString().slice(0, 10);
  }

  function _isPast(iso) {
    return iso < new Date().toISOString().slice(0, 10);
  }

  function _sourceIcon(source) {
    if (source === 'places') return 'star';
    if (source === 'osm')    return 'map-pin';
    return 'map-trifold';
  }

  // ----------------------------------------------------------
  // INIT
  // ----------------------------------------------------------
  async function init(container, appState) {
    _container = container;
    _appState  = appState;
    _render();
    try { _userPos = await API.getLocation(); } catch {}
    _loadData();
  }

  function refresh() { _loadData(); }
  function onDogChange() {}
  function openNew() { _showCreateForm(); }

  // ----------------------------------------------------------
  // RENDER — Grundstruktur
  // ----------------------------------------------------------
  function _render() {
    _container.innerHTML = `
      <div class="walks-layout">

        <!-- Toolbar -->
        <div class="by-toolbar">
          <div class="walks-view-toggle" id="walks-view-toggle">
            <button class="walks-view-btn active" data-view="liste">${UI.icon('list')} Liste</button>
            <button class="walks-view-btn" data-view="karte">${UI.icon('map-trifold')} Karte</button>
          </div>
          <button class="btn btn-primary btn-sm" id="walks-create-btn">${UI.icon('plus')} Treffen planen</button>
        </div>

        <!-- Liste -->
        <div id="walks-list-view" class="walks-content">
          <div id="walks-list">
            <p style="color:var(--c-text-secondary);text-align:center;padding:var(--space-8)">Lädt…</p>
          </div>
        </div>

        <!-- Karte -->
        <div id="walks-map-view" class="walks-content" style="display:none">
          <div id="walks-map" class="walks-map"></div>
        </div>

      </div>
    `;

    document.getElementById('walks-view-toggle').addEventListener('click', e => {
      const btn = e.target.closest('.walks-view-btn');
      if (!btn) return;
      _switchView(btn.dataset.view);
    });

    document.getElementById('walks-create-btn').addEventListener('click', () => {
      if (!_appState.user) {
        UI.toast.warning('Bitte zuerst anmelden.');
        App.navigate('settings');
        return;
      }
      _showCreateForm();
    });
  }

  function _switchView(view) {
    _view = view;
    document.querySelectorAll('.walks-view-btn').forEach(b =>
      b.classList.toggle('active', b.dataset.view === view));

    // Desktop: beide Panels bleiben via CSS sichtbar
    if (window.innerWidth >= 1024) return;

    document.getElementById('walks-list-view').style.display = view === 'liste' ? '' : 'none';
    document.getElementById('walks-map-view').style.display  = view === 'karte' ? '' : 'none';

    if (view === 'karte') {
      UI.loadLeaflet().then(() => {
        _initMap();
        setTimeout(() => _map?.invalidateSize(), 150);
        setTimeout(() => _map?.invalidateSize(), 400);
      });
    }
  }

  // ----------------------------------------------------------
  // Daten laden
  // ----------------------------------------------------------
  async function _loadData() {
    try {
      _data = await API.walks.list(
        _userPos?.lat ?? null,
        _userPos?.lon ?? null
      );
      _renderList();
      _renderMarkers();
      // Desktop: Karte direkt initialisieren (beide Panels sichtbar)
      if (window.innerWidth >= 1024) {
        UI.loadLeaflet().then(() => {
          _initMap();
          setTimeout(() => _map?.invalidateSize(), 150);
          setTimeout(() => _map?.invalidateSize(), 400);
        });
      }
    } catch (err) {
      UI.toast.error(err.message || 'Fehler beim Laden.');
    }
  }

  // ----------------------------------------------------------
  // Liste rendern
  // ----------------------------------------------------------
  function _renderList() {
    const el = document.getElementById('walks-list');
    if (!el) return;

    if (!_data.length) {
      el.innerHTML = `
        <div style="text-align:center;padding:var(--space-10) var(--space-4)">
          <div style="font-size:3rem;margin-bottom:var(--space-3)">${UI.icon('dog')}</div>
          <p style="color:var(--c-text-secondary)">Noch keine Treffen in deiner Nähe.</p>
          <button class="btn btn-primary" style="margin-top:var(--space-4)" id="walks-first-btn">
            Erstes Treffen planen
          </button>
        </div>`;
      document.getElementById('walks-first-btn')?.addEventListener('click', _showCreateForm);
      return;
    }

    // Heute + zukünftige Treffen
    const heute    = _data.filter(w => _isToday(w.datum));
    const upcoming = _data.filter(w => !_isToday(w.datum) && !_isPast(w.datum));

    let html = '';

    if (heute.length) {
      html += `<div class="by-section-label">${UI.icon('star')} Heute</div>`;
      html += heute.map(w => _walkCardHTML(w)).join('');
    }

    if (upcoming.length) {
      html += `<div class="by-section-label">${UI.icon('calendar-dots')} Demnächst</div>`;
      html += upcoming.map(w => _walkCardHTML(w)).join('');
    }

    el.innerHTML = `<div class="walks-list-inner">${html}</div>`;

    el.querySelectorAll('.walks-card').forEach(card => {
      card.addEventListener('click', () => _openDetail(parseInt(card.dataset.id)));
    });

    el.querySelectorAll('.wk-note-btn').forEach(btn => {
      btn.addEventListener('click', e => {
        e.stopPropagation();
        _openNoteModal(
          'walk',
          parseInt(btn.dataset.wkNoteId),
          btn.dataset.wkNoteLabel,
          btn.dataset.wkNoteOrt || null
        );
      });
    });
  }

  function _walkCardHTML(w) {
    const isOwn    = _appState.user?.id === w.user_id;
    const isFull   = w.status === 'voll' || w.teilnehmer_count >= w.max_teilnehmer;
    const today    = _isToday(w.datum);
    const spots    = w.max_teilnehmer - w.teilnehmer_count;

    return `
      <div class="walks-card ${today ? 'walks-card--today' : ''}" data-id="${w.id}">
        <div class="walks-card-date">
          <div class="walks-card-day">${_fmtDateShort(w.datum)}</div>
          <div class="walks-card-time">${w.uhrzeit}</div>
        </div>
        <div class="walks-card-body">
          <div class="walks-card-title">${UI.escape(w.titel)}</div>
          ${w.ort_name ? `<div class="walks-card-ort">${UI.icon('map-pin')} ${UI.escape(w.ort_name)}</div>` : ''}
          <div class="walks-card-meta">
            <span class="walks-badge ${isFull ? 'walks-badge--full' : 'walks-badge--open'}">
              ${isFull ? '🔴 Voll' : `🟢 ${spots} Platz${spots !== 1 ? 'e' : ''} frei`}
            </span>
            <span class="walks-badge">${UI.icon('paw-print')} ${w.teilnehmer_count}/${w.max_teilnehmer}</span>
            ${isOwn ? '<span class="walks-badge walks-badge--own">Mein Treffen</span>' : ''}
          </div>
        </div>
        <div style="display:flex;flex-direction:column;align-items:flex-end;gap:var(--space-1)">
          <div class="walks-card-arrow">›</div>
          ${_appState.user ? `<button class="btn-icon wk-note-btn"
                                data-wk-note-id="${w.id}"
                                data-wk-note-label="${UI.escape(w.titel + ' ' + w.datum)}"
                                data-wk-note-ort="${UI.escape(w.ort_name || '')}"
                                title="Notiz" style="color:var(--c-text-muted);font-size:var(--text-xs)"
                                onclick="event.stopPropagation()">
                                ${UI.icon('note-pencil')}</button>` : ''}
        </div>
      </div>`;
  }

  // ----------------------------------------------------------
  // Leaflet + Karte
  // ----------------------------------------------------------
  function _initMap() {
    const el = document.getElementById('walks-map');
    if (!el || !window.L || _map) return;
    const center = _userPos ? [_userPos.lat, _userPos.lon] : [51.1657, 10.4515];
    _map = L.map('walks-map', { zoomControl: true, attributionControl: false })
             .setView(center, _userPos ? 12 : 6);
    L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 }).addTo(_map);
    _renderMarkers();
  }

  function _renderMarkers() {
    if (!_map || !window.L) return;
    _markers.forEach(m => m.remove());
    _markers = [];
    _data.forEach(w => {
      if (!w.lat || !w.lon) return;
      const isFull = w.status === 'voll' || w.teilnehmer_count >= w.max_teilnehmer;
      const color  = _isToday(w.datum) ? 'var(--c-primary)' : (isFull ? '#6B7280' : '#22C55E');
      const m = UI.leafletMarker({ lat: w.lat, lon: w.lon, color, icon: UI.icon('dog') })
        .addTo(_map)
        .bindTooltip(`${w.titel} · ${_fmtDateShort(w.datum)} ${w.uhrzeit}`, { direction: 'top', offset: [0,-16] })
        .on('click', () => _openDetail(w.id));
      _markers.push(m);
    });
  }

  // ----------------------------------------------------------
  // RSVP-Status → Label + Farbe
  // ----------------------------------------------------------
  function _rsvpBadge(status) {
    if (status === 'yes')     return `<span class="walks-rsvp-badge walks-rsvp--yes">Zusage</span>`;
    if (status === 'maybe')   return `<span class="walks-rsvp-badge walks-rsvp--maybe">Vielleicht</span>`;
    if (status === 'no')      return `<span class="walks-rsvp-badge walks-rsvp--no">Absage</span>`;
    return `<span class="walks-rsvp-badge walks-rsvp--invited">Eingeladen</span>`;
  }

  function _avatarInitials(name) {
    const parts = (name || '?').trim().split(/\s+/);
    const initials = parts.length >= 2
      ? parts[0][0] + parts[parts.length - 1][0]
      : parts[0].slice(0, 2);
    return initials.toUpperCase();
  }

  function _invitationRowHTML(inv) {
    return `
      <div class="walks-invitation-row">
        <div class="walks-inv-avatar">${_avatarInitials(inv.user_name)}</div>
        <div class="walks-inv-info">
          <div class="walks-inv-name">${UI.escape(inv.user_name)}</div>
          ${inv.hunde ? `<div class="walks-inv-hunde">${UI.icon('dog')} ${UI.escape(inv.hunde)}</div>` : ''}
        </div>
        <div class="walks-inv-badge">${_rsvpBadge(inv.status)}</div>
      </div>`;
  }

  // ----------------------------------------------------------
  // Detail-Modal
  // ----------------------------------------------------------
  async function _openDetail(walkId) {
    let walk, participantData;
    try {
      walk = await API.walks.get(walkId);
      if (_appState.user) {
        try { participantData = await API.walks.participants(walkId); } catch {}
      }
    } catch (err) {
      UI.toast.error(err.message);
      return;
    }

    const isOwn      = _appState.user?.id === walk.user_id;
    const isJoined   = walk.teilnehmer?.some(t => t.user_id === _appState.user?.id);
    const isFull     = walk.status === 'voll' || walk.teilnehmer_count >= walk.max_teilnehmer;
    const isPast     = _isPast(walk.datum);
    const spots      = walk.max_teilnehmer - walk.teilnehmer_count;
    const myRsvp     = participantData?.my_rsvp ?? null;
    const isInvited  = !!myRsvp;
    const invitations = participantData?.invitations ?? [];

    // Teilnehmerliste (join-Teilnehmer, klassisch)
    const teilnehmerHTML = walk.teilnehmer?.length
      ? walk.teilnehmer.map(t => `
          <div class="walks-participant">
            <div class="walks-inv-avatar walks-inv-avatar--sm">${_avatarInitials(t.user_name)}</div>
            <span class="walks-participant-name">${UI.escape(t.user_name)}</span>
            ${t.hunde ? `<span class="walks-participant-hunde">${UI.icon('dog')} ${UI.escape(t.hunde)}</span>` : ''}
          </div>`).join('')
      : '';

    // Einladungsliste
    const invListHTML = invitations.length
      ? invitations.map(inv => _invitationRowHTML(inv)).join('')
      : `<p style="color:var(--c-text-muted);font-size:var(--text-sm)">Noch keine Einladungen.</p>`;

    // RSVP-Section für eingeladene Nutzer
    const rsvpSectionHTML = (isInvited && !isOwn) ? `
      <div class="walks-rsvp-section" id="wd-rsvp-section">
        <div class="walks-detail-section-label">${UI.icon('check-circle')} Deine Antwort</div>
        <div class="walks-rsvp-buttons">
          <button type="button" class="walks-rsvp-btn ${myRsvp === 'yes' ? 'active' : ''}" data-rsvp="yes">
            ${UI.icon('check')} Zusagen
          </button>
          <button type="button" class="walks-rsvp-btn ${myRsvp === 'maybe' ? 'active' : ''}" data-rsvp="maybe">
            ${UI.icon('question')} Vielleicht
          </button>
          <button type="button" class="walks-rsvp-btn ${myRsvp === 'no' ? 'active' : ''}" data-rsvp="no">
            ${UI.icon('x')} Absagen
          </button>
        </div>
      </div>
    ` : '';

    const body = `
      <div class="walks-detail-header">
        <div class="walks-detail-date">
          ${_fmtDate(walk.datum)}<br>
          <strong>um ${walk.uhrzeit} Uhr</strong>
        </div>
        ${walk.ort_name ? `<div style="margin-top:var(--space-2);color:var(--c-text-secondary)">${UI.icon('map-pin')} ${UI.escape(walk.ort_name)}</div>` : ''}
        <div style="margin-top:var(--space-2);display:flex;gap:var(--space-2);flex-wrap:wrap">
          <span class="walks-badge ${isFull ? 'walks-badge--full' : 'walks-badge--open'}">
            ${isFull ? '🔴 Voll' : `🟢 ${spots} Platz${spots !== 1 ? 'e' : ''} frei`}
          </span>
          <span class="walks-badge">${UI.icon('paw-print')} ${walk.teilnehmer_count}/${walk.max_teilnehmer} Teilnehmer</span>
          ${isOwn ? '<span class="walks-badge walks-badge--own">Dein Treffen</span>' : ''}
        </div>
      </div>

      ${walk.beschreibung ? `
        <p style="margin:var(--space-4) 0;color:var(--c-text-secondary)">${UI.escape(walk.beschreibung)}</p>
      ` : ''}

      ${rsvpSectionHTML}

      <div class="walks-detail-section">
        <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:var(--space-2)">
          <div class="walks-detail-section-label" style="margin-bottom:0">${UI.icon('users')} Einladungen</div>
          ${isOwn && !isPast ? `<button type="button" class="btn btn-secondary btn-sm" id="wd-invite-btn">${UI.icon('user-plus')} Einladen</button>` : ''}
        </div>
        <div id="wd-inv-list">${invListHTML}</div>
      </div>

      ${walk.teilnehmer?.length ? `
        <div class="walks-detail-section">
          <div class="walks-detail-section-label">${UI.icon('check-circle')} Beigetreten (${walk.teilnehmer_count}/${walk.max_teilnehmer})</div>
          ${teilnehmerHTML}
        </div>
      ` : ''}

      <div class="walks-detail-section">
        <div class="walks-detail-section-label">${UI.icon('star')} Bewertung</div>
        <div id="wd-rating-${walk.id}"></div>
      </div>

      <p style="color:var(--c-text-muted);font-size:0.8rem;margin-top:var(--space-4)">
        Veranstaltet von ${UI.escape(walk.veranstalter_name || 'Unbekannt')}
      </p>

      ${isOwn && !isPast ? `
        <div id="wd-cancel-wrap" style="margin-top:var(--space-3)">
          <button type="button" class="btn btn-ghost btn-sm" id="wd-cancel-walk"
                  style="color:var(--c-danger);width:100%">
            ${UI.icon('x-circle')} Treffen stornieren
          </button>
        </div>` : ''}

      ${isJoined && !isOwn ? `
        <div id="wd-leave-wrap" style="margin-top:var(--space-3)">
          <button type="button" class="btn btn-ghost btn-sm" id="wd-leave"
                  style="color:var(--c-danger);width:100%">
            ${UI.icon('sign-out')} Nicht mehr teilnehmen
          </button>
        </div>` : ''}
    `;

    let footer;
    if (isOwn) {
      footer = `
        <button type="button" class="btn btn-secondary flex-1" id="wd-edit">${UI.icon('pencil-simple')} Bearbeiten</button>
        <button type="button" class="btn btn-primary flex-1" id="wd-close">Schließen</button>
      `;
    } else if (!_appState.user) {
      footer = `
        <button type="button" class="btn btn-secondary flex-1" id="wd-close">Schließen</button>
        <button type="button" class="btn btn-primary flex-1" id="wd-login">Anmelden zum Beitreten</button>
      `;
    } else if (isJoined) {
      footer = `
        <button type="button" class="btn btn-primary flex-1" id="wd-close">Schließen</button>
      `;
    } else if (isPast || isFull) {
      footer = `<button type="button" class="btn btn-primary flex-1" id="wd-close">Schließen</button>`;
    } else {
      footer = `
        <button type="button" class="btn btn-secondary flex-1" id="wd-close">Schließen</button>
        <button type="button" class="btn btn-primary flex-1" id="wd-join">${UI.icon('dog')} Mitmachen</button>
      `;
    }

    UI.modal.open({ title: `${UI.icon('dog')} ${walk.titel}`, body, footer });

    // Bewertungskomponente initialisieren (nur nach abgelaufenem Treffen sinnvoll, aber immer anzeigen)
    UI.ratingStars({
      containerId: `wd-rating-${walk.id}`,
      targetType:  'walk',
      targetId:    walk.id,
      isLoggedIn:  !!_appState.user,
    });

    document.getElementById('wd-close')?.addEventListener('click', UI.modal.close);

    document.getElementById('wd-login')?.addEventListener('click', () => {
      UI.modal.close();
      App.navigate('settings');
    });

    document.getElementById('wd-edit')?.addEventListener('click', () => {
      UI.modal.close();
      _showEditForm(walk);
    });

    // Einladen-Button
    document.getElementById('wd-invite-btn')?.addEventListener('click', () => {
      UI.modal.close();
      _showInviteModal(walk);
    });

    // RSVP-Buttons
    document.querySelectorAll('.walks-rsvp-btn').forEach(btn => {
      btn.addEventListener('click', async () => {
        const status = btn.dataset.rsvp;
        try {
          await API.walks.rsvp(walk.id, status);
          // Buttons aktualisieren
          document.querySelectorAll('.walks-rsvp-btn').forEach(b => {
            b.classList.toggle('active', b.dataset.rsvp === status);
          });
          UI.toast.success(
            status === 'yes' ? 'Zugesagt!' :
            status === 'maybe' ? 'Antwort: Vielleicht.' :
            'Abgesagt.'
          );
        } catch (err) { UI.toast.error(err.message); }
      });
    });

    // Stornieren: Zwei-Klick-Pattern (kein UI.modal.confirm im Modal)
    let _cancelPending = false;
    document.getElementById('wd-cancel-walk')?.addEventListener('click', async () => {
      const btn = document.getElementById('wd-cancel-walk');
      if (!_cancelPending) {
        _cancelPending = true;
        btn.textContent = 'Wirklich stornieren? (nochmal tippen)';
        btn.style.fontWeight = 'var(--weight-semibold)';
        setTimeout(() => {
          _cancelPending = false;
          if (btn) {
            btn.innerHTML = `${UI.icon('x-circle')} Treffen stornieren`;
            btn.style.fontWeight = '';
          }
        }, 3000);
        return;
      }
      _cancelPending = false;
      try {
        await API.walks.cancel(walk.id);
        _data = _data.filter(w => w.id !== walk.id);
        UI.modal.close();
        _renderList();
        _renderMarkers();
        UI.toast.success('Treffen storniert.');
      } catch (err) { UI.toast.error(err.message); }
    });

    document.getElementById('wd-join')?.addEventListener('click', () => {
      UI.modal.close();
      _showJoinForm(walk);
    });

    // Austreten: Zwei-Klick-Pattern
    let _leavePending = false;
    document.getElementById('wd-leave')?.addEventListener('click', async () => {
      const btn = document.getElementById('wd-leave');
      if (!_leavePending) {
        _leavePending = true;
        btn.textContent = 'Wirklich austreten? (nochmal tippen)';
        btn.style.fontWeight = 'var(--weight-semibold)';
        setTimeout(() => {
          _leavePending = false;
          if (btn) {
            btn.innerHTML = `${UI.icon('sign-out')} Nicht mehr teilnehmen`;
            btn.style.fontWeight = '';
          }
        }, 3000);
        return;
      }
      _leavePending = false;
      try {
        const res = await API.walks.leave(walk.id);
        const idx = _data.findIndex(w => w.id === walk.id);
        if (idx !== -1) _data[idx].teilnehmer_count = res.teilnehmer_count;
        UI.modal.close();
        _renderList();
        UI.toast.success('Du nimmst nicht mehr teil.');
      } catch (err) { UI.toast.error(err.message); }
    });
  }

  // ----------------------------------------------------------
  // Freunde einladen
  // ----------------------------------------------------------
  async function _showInviteModal(walk) {
    let candidates;
    try {
      candidates = await API.walks.inviteCandidates(walk.id);
    } catch (err) {
      UI.toast.error(err.message);
      return;
    }

    const listHTML = candidates.length
      ? candidates.map(f => `
          <div class="walks-invite-row" data-friend-id="${f.friend_id}" data-friend-name="${UI.escape(f.friend_name)}">
            <div class="walks-inv-avatar">${_avatarInitials(f.friend_name)}</div>
            <div class="walks-inv-name" style="flex:1">${UI.escape(f.friend_name)}</div>
            <button type="button" class="btn btn-primary btn-sm walks-invite-send">
              ${UI.icon('paper-plane-tilt')} Einladen
            </button>
          </div>`).join('')
      : `<p style="color:var(--c-text-muted)">Alle Freunde wurden bereits eingeladen.</p>`;

    const body = `
      <p style="color:var(--c-text-secondary);margin-bottom:var(--space-3)">
        ${_fmtDate(walk.datum)} · ${walk.uhrzeit} Uhr
        ${walk.ort_name ? `· ${UI.escape(walk.ort_name)}` : ''}
      </p>
      <div id="invite-list">${listHTML}</div>
    `;

    const footer = `
      <button type="button" class="btn btn-secondary flex-1" id="invite-back">Zurück</button>
    `;

    UI.modal.open({ title: `${UI.icon('user-plus')} Freunde einladen`, body, footer });

    document.getElementById('invite-back')?.addEventListener('click', () => {
      UI.modal.close();
      _openDetail(walk.id);
    });

    document.querySelectorAll('.walks-invite-send').forEach(btn => {
      btn.addEventListener('click', async () => {
        const row      = btn.closest('.walks-invite-row');
        const friendId = parseInt(row.dataset.friendId);
        const name     = row.dataset.friendName;
        await UI.asyncButton(btn, async () => {
          await API.walks.invite(walk.id, friendId);
          row.innerHTML = `
            <div class="walks-inv-avatar">${_avatarInitials(name)}</div>
            <div class="walks-inv-name" style="flex:1">${UI.escape(name)}</div>
            <span class="walks-rsvp-badge walks-rsvp--invited">Eingeladen</span>
          `;
          UI.toast.success(`${name} eingeladen.`);
        });
      });
    });
  }

  // ----------------------------------------------------------
  // Beitreten-Formular (Hunde wählen)
  // ----------------------------------------------------------
  function _showJoinForm(walk) {
    const dogs = _appState.dogs || [];
    const dogsHtml = dogs.length
      ? dogs.map(d => `
          <label style="display:flex;align-items:center;gap:var(--space-2);cursor:pointer;
                         padding:var(--space-2) 0">
            <input type="checkbox" name="dog" value="${d.id}" checked>
            ${UI.icon('dog')} ${UI.escape(d.name)}
          </label>`).join('')
      : `<p style="color:var(--c-text-muted)">Keine Hunde im Profil — du kannst trotzdem mitmachen.</p>`;

    const body = `
      <p style="color:var(--c-text-secondary);margin-bottom:var(--space-4)">
        ${_fmtDate(walk.datum)} um ${walk.uhrzeit} Uhr<br>
        ${walk.ort_name ? `${UI.icon('map-pin')} ${UI.escape(walk.ort_name)}` : ''}
      </p>
      <form id="join-form" autocomplete="off">
        <div class="form-group">
          <label class="form-label">Mit welchen Hunden?</label>
          ${dogsHtml}
        </div>
      </form>
    `;

    const footer = `
      <button type="button" class="btn btn-secondary flex-1" id="join-cancel">Abbrechen</button>
      <button type="submit" form="join-form" class="btn btn-primary flex-1" id="join-confirm">${UI.icon('dog')} Mitmachen</button>
    `;

    UI.modal.open({ title: `Treffen beitreten`, body, footer });

    document.getElementById('join-cancel')?.addEventListener('click', UI.modal.close);

    document.getElementById('join-form')?.addEventListener('submit', async e => {
      e.preventDefault();
      const btn     = document.getElementById('join-confirm');
      const checked = [...document.querySelectorAll('[name="dog"]:checked')];
      const dogIds  = checked.map(cb => parseInt(cb.value));

      await UI.asyncButton(btn, async () => {
        const res = await API.walks.join(walk.id, dogIds);
        const idx = _data.findIndex(w => w.id === walk.id);
        if (idx !== -1) _data[idx].teilnehmer_count = res.teilnehmer_count;
        UI.modal.close();
        _renderList();
        _renderMarkers();
        UI.toast.success(`Du nimmst teil! 🎉`);
      });
    });
  }

  // ----------------------------------------------------------
  // Treffen erstellen / bearbeiten — Formular
  // ----------------------------------------------------------
  function _showCreateForm(prefill = {}) {
    const today = new Date().toISOString().slice(0, 10);
    _showWalkForm(null, { datum: today, uhrzeit: '10:00', ...prefill });
  }

  function _showEditForm(walk) {
    _showWalkForm(walk);
  }

  function _showWalkForm(walk, defaults = {}) {
    const isEdit = !!walk;
    const v = walk || defaults;

    // Location-State (verwaltet außerhalb des DOM)
    let _locLat  = v.lat  != null ? parseFloat(v.lat)  : null;
    let _locLon  = v.lon  != null ? parseFloat(v.lon)  : null;
    let _locName = v.ort_name || null;

    const _pinSvg = '<svg xmlns="http://www.w3.org/2000/svg" width="28" height="36" viewBox="0 0 32 40"><path d="M16 0C7.163 0 0 7.163 0 16c0 10 16 24 16 24S32 26 32 16C32 7.163 24.837 0 16 0z" fill="#C4843A"/><circle cx="16" cy="16" r="7" fill="white"/></svg>';

    const body = `
      <form id="walk-form" autocomplete="off">

        <div class="form-group">
          <label class="form-label">Titel *</label>
          <input class="form-control" type="text" name="titel"
                 value="${UI.escape(v.titel || '')}"
                 placeholder="z. B. Sonntagsspaziergang im Stadtpark" required>
        </div>

        <div style="display:grid;grid-template-columns:1fr 1fr;gap:var(--space-3)">
          <div class="form-group">
            <label class="form-label">Datum *</label>
            <input class="form-control" type="date" name="datum"
                   value="${UI.escape(v.datum || '')}" required>
          </div>
          <div class="form-group">
            <label class="form-label">Uhrzeit *</label>
            <input class="form-control" type="time" name="uhrzeit"
                   value="${UI.escape(v.uhrzeit || '10:00')}" required>
          </div>
        </div>

        <div class="form-group" id="wf-location-group">
          <label class="form-label">Treffpunkt</label>

          <!-- Mini-Karte -->
          <div style="position:relative">
            <div id="wf-map-wrap" style="border-radius:var(--radius-md);overflow:hidden;height:200px;background:var(--c-surface-2)"></div>
            <button type="button" id="wf-map-pin-here" style="
              position:absolute;bottom:10px;left:50%;transform:translateX(-50%);
              z-index:1000;background:var(--c-primary);color:#fff;border:none;
              border-radius:var(--radius-full);padding:6px 14px;font-size:var(--text-xs);
              font-weight:600;box-shadow:var(--shadow-md);cursor:pointer;
              display:flex;align-items:center;gap:6px;white-space:nowrap">
              ${UI.icon('map-pin')} Pin hier setzen
            </button>
          </div>

          <!-- Ort-Chip -->
          <div style="margin-top:var(--space-2)">
            <div id="wf-location-chip-wrap" style="${_locName ? '' : 'display:none'}">
              <div class="diary-location-chip">
                ${UI.icon('map-pin')}
                <span id="wf-location-label">${UI.escape(_locName || '')}</span>
                <button type="button" id="wf-location-clear" aria-label="Name entfernen">
                  ${UI.icon('x')}
                </button>
              </div>
            </div>

            <div style="display:flex;gap:var(--space-2);margin-top:var(--space-2)">
              <button type="button" class="btn btn-danger btn-sm" id="wf-coords-clear">Ort entfernen</button>
              <button type="button" class="btn btn-secondary flex-1" id="wf-location-btn">
                ${UI.icon('map-pin')}
                <span id="wf-location-btn-label">${_locLat ? 'POI suchen' : 'GPS → POI suchen'}</span>
              </button>
            </div>

            <!-- Vorschläge -->
            <div id="wf-location-suggestions" style="display:none;margin-top:var(--space-2)"></div>
          </div>

          <!-- Versteckte Koordinaten-Felder -->
          <input type="hidden" name="lat" id="wf-lat" value="${_locLat || ''}">
          <input type="hidden" name="lon" id="wf-lon" value="${_locLon || ''}">
          <input type="hidden" name="ort_name" id="wf-ort-name" value="${UI.escape(_locName || '')}">
        </div>

        <div class="form-group">
          <label class="form-label">Max. Teilnehmer</label>
          <input class="form-control" type="number" name="max_teilnehmer"
                 value="${v.max_teilnehmer || 10}" min="2" max="50">
        </div>

        <div class="form-group">
          <label class="form-label">Beschreibung <span style="color:var(--c-text-secondary)">(optional)</span></label>
          <textarea class="form-control" name="beschreibung" rows="3"
                    placeholder="Treffpunkt-Details, Streckenlänge, Hundefreundlichkeit…">${UI.escape(v.beschreibung || '')}</textarea>
        </div>

      </form>
    `;

    const footer = `
      <div style="display:flex;flex-direction:column;gap:var(--space-2);width:100%">
        <button type="submit" form="walk-form" class="btn btn-primary" style="width:100%">
          ${isEdit ? `${UI.icon('floppy-disk')} Speichern` : `${UI.icon('calendar-dots')} Treffen planen`}
        </button>
        <button type="button" class="btn btn-secondary" id="wf-cancel">Abbrechen</button>
      </div>
    `;

    UI.modal.open({ title: isEdit ? `${UI.icon('pencil-simple')} Treffen bearbeiten` : `${UI.icon('dog')} Treffen planen`, body, footer });

    document.getElementById('wf-cancel')?.addEventListener('click', UI.modal.close);

    // --- Mini-Karte ---
    let _miniMap = null, _miniMarker = null, _mapEditing = false;

    const _mkIcon = () => L.divIcon({ html: _pinSvg, className: '', iconSize: [28, 36], iconAnchor: [14, 36] });

    function _placeMarker(lat, lon) {
      if (_miniMarker) { _miniMarker.setLatLng([lat, lon]); return; }
      _miniMarker = L.marker([lat, lon], { draggable: true, icon: _mkIcon() }).addTo(_miniMap);
      _miniMarker.on('dragend', () => {
        const p = _miniMarker.getLatLng();
        _locLat = p.lat; _locLon = p.lng;
        document.getElementById('wf-lat').value = _locLat;
        document.getElementById('wf-lon').value = _locLon;
        document.getElementById('wf-location-btn-label').textContent = 'POI suchen';
      });
    }

    function _setCoords(lat, lon) {
      _locLat = lat; _locLon = lon;
      document.getElementById('wf-lat').value = lat;
      document.getElementById('wf-lon').value = lon;
    }

    function _setName(name) {
      _locName = name;
      document.getElementById('wf-location-label').textContent = name;
      document.getElementById('wf-location-chip-wrap').style.display = '';
      document.getElementById('wf-ort-name').value = name;
      document.getElementById('wf-location-suggestions').style.display = 'none';
    }

    UI.loadLeaflet().then(() => {
      setTimeout(() => {
        const lat  = _locLat || 48.0, lon = _locLon || 11.9, zoom = _locLat ? 15 : 7;
        _miniMap = L.map('wf-map-wrap', {
          zoomControl: true, attributionControl: false,
          dragging: true, scrollWheelZoom: false,
        }).setView([lat, lon], zoom);
        L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 19 })
          .addTo(_miniMap);
        _miniMap.invalidateSize();
        if (_locLat) _placeMarker(lat, lon);
        _miniMap.on('click', e => {
          _setCoords(e.latlng.lat, e.latlng.lng);
          _placeMarker(_locLat, _locLon);
          document.getElementById('wf-location-btn-label').textContent = 'POI suchen';
        });
        document.getElementById('wf-map-pin-here')?.addEventListener('click', () => {
          const c = _miniMap.getCenter();
          _setCoords(c.lat, c.lng);
          _placeMarker(c.lat, c.lng);
          document.getElementById('wf-location-btn-label').textContent = 'POI suchen';
        });
      }, 150);
    });

    // Ort-Name-Chip entfernen
    document.getElementById('wf-location-clear')?.addEventListener('click', () => {
      _locName = null;
      document.getElementById('wf-location-chip-wrap').style.display = 'none';
      document.getElementById('wf-ort-name').value = '';
    });

    // Koordinaten + Name entfernen (Zwei-Klick)
    const clearBtn = document.getElementById('wf-coords-clear');
    let _clearPending = false;
    clearBtn?.addEventListener('click', () => {
      if (!_clearPending) {
        _clearPending = true;
        clearBtn.textContent = 'Wirklich entfernen?';
        clearBtn.style.color = 'var(--c-danger)';
        setTimeout(() => {
          _clearPending = false;
          if (clearBtn) {
            clearBtn.textContent = 'Ort entfernen';
            clearBtn.style.color = '';
          }
        }, 3000);
        return;
      }
      _clearPending = false;
      clearBtn.textContent = 'Ort entfernen';
      clearBtn.style.color = '';
      _locLat = null; _locLon = null; _locName = null;
      document.getElementById('wf-lat').value = '';
      document.getElementById('wf-lon').value = '';
      document.getElementById('wf-ort-name').value = '';
      document.getElementById('wf-location-chip-wrap').style.display = 'none';
      document.getElementById('wf-location-suggestions').style.display = 'none';
      document.getElementById('wf-location-btn-label').textContent = 'GPS → POI suchen';
      if (_miniMarker) { _miniMarker.remove(); _miniMarker = null; }
      if (_miniMap) { _miniMap.setView([48.0, 11.9], 7); }
    });

    // GPS → POI-Suche (wie diary.js)
    async function _showSuggestions() {
      const btn = document.getElementById('wf-location-btn');
      UI.setLoading(btn, true);
      try {
        let lat = _locLat, lon = _locLon;
        if (lat == null || lon == null) {
          const pos = await API.getLocation({ enableHighAccuracy: true });
          lat = pos.lat; lon = pos.lon;
          _setCoords(lat, lon);
          if (_miniMap) {
            _miniMap.setView([lat, lon], 15);
            _placeMarker(lat, lon);
            if (_miniMarker) _miniMarker.dragging.disable();
          }
          document.getElementById('wf-location-btn-label').textContent = 'POI suchen';
        }

        const suggestions = _appState.user
          ? await API.walks.nearby(lat, lon)
          : [];

        const sugEl = document.getElementById('wf-location-suggestions');
        if (!suggestions.length) {
          sugEl.innerHTML = '<p style="font-size:var(--text-sm);color:var(--c-text-secondary);padding:var(--space-2) 0">Keine Orte in der Nähe gefunden.</p>';
        } else {
          sugEl.innerHTML = suggestions.map(s => `
            <button type="button" class="diary-location-suggestion"
                    data-name="${UI.escape(s.name)}" data-lat="${s.lat}" data-lon="${s.lon}">
              ${UI.icon(_sourceIcon(s.source))}
              <span>${UI.escape(s.name)}</span>
              <small>${s.distance_m < 1000 ? s.distance_m + ' m' : (s.distance_m / 1000).toFixed(1) + ' km'}</small>
            </button>`).join('');
          sugEl.querySelectorAll('.diary-location-suggestion').forEach(el => {
            el.addEventListener('click', () => {
              const slat = parseFloat(el.dataset.lat);
              const slon = parseFloat(el.dataset.lon);
              _setCoords(slat, slon);
              _setName(el.dataset.name);
              if (_miniMap) {
                _miniMap.setView([slat, slon], 16);
                _placeMarker(slat, slon);
                if (_miniMarker) _miniMarker.dragging.disable();
              }
            });
          });
        }
        sugEl.style.display = '';
      } catch (err) {
        UI.toast.error(err?.message?.includes('GPS') || _locLat == null
          ? 'GPS nicht verfügbar.' : 'Ortssuche fehlgeschlagen.');
      } finally {
        UI.setLoading(btn, false);
      }
    }

    document.getElementById('wf-location-btn')?.addEventListener('click', _showSuggestions);

    // Formular absenden
    document.getElementById('walk-form')?.addEventListener('submit', async e => {
      e.preventDefault();
      const btn = document.querySelector('[form="walk-form"][type="submit"]') || e.target.querySelector('[type="submit"]');
      const fd  = UI.formData(e.target);

      // Koordinaten aus State lesen (nicht aus fd, da hidden)
      const lat = _locLat;
      const lon = _locLon;

      if (!lat || !lon) {
        UI.toast.warning('Bitte einen Treffpunkt auf der Karte wählen oder GPS nutzen.');
        return;
      }

      await UI.asyncButton(btn, async () => {
        const payload = {
          titel:          fd.titel?.trim(),
          datum:          fd.datum,
          uhrzeit:        fd.uhrzeit,
          lat:            parseFloat(lat),
          lon:            parseFloat(lon),
          ort_name:       _locName || null,
          max_teilnehmer: parseInt(fd.max_teilnehmer) || 10,
          beschreibung:   fd.beschreibung || null,
        };

        if (isEdit) {
          const updated = await API.walks.update(walk.id, payload);
          const idx = _data.findIndex(w => w.id === walk.id);
          if (idx !== -1) _data[idx] = { ..._data[idx], ...updated };
          UI.toast.success('Treffen aktualisiert.');
        } else {
          const created = await API.walks.create(payload);
          _data.unshift({ ...created, teilnehmer_count: 0 });
          UI.toast.success('Treffen geplant! 🎉');
        }

        UI.modal.close();
        _renderList();
        _renderMarkers();
      });
    });
  }

  // ----------------------------------------------------------
  // Notiz-Modal (Custom DOM — kein UI.modal um Konflikte zu vermeiden)
  // ----------------------------------------------------------
  async function _openNoteModal(parentType, parentId, parentLabel, locationName) {
    let existingNote = null;
    try { existingNote = await API.notes.get(parentType, String(parentId)); } catch {}

    const ovl = document.createElement('div');
    ovl.style.cssText = 'position:fixed;inset:0;z-index:1200;background:rgba(0,0,0,0.55);display:flex;align-items:flex-end;justify-content:center';
    ovl.innerHTML = `
      <div style="width:100%;max-width:600px;background:var(--c-surface);border-radius:var(--radius-lg) var(--radius-lg) 0 0;
                  padding:var(--space-4);box-sizing:border-box;max-height:80vh;display:flex;flex-direction:column">
        <div style="display:flex;align-items:center;gap:var(--space-3);margin-bottom:var(--space-3)">
          <svg class="ph-icon" aria-hidden="true" style="color:var(--c-primary)"><use href="/icons/phosphor.svg#note-pencil"></use></svg>
          <span style="font-weight:600;flex:1"><svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#note-pencil"></use></svg> Notiz — ${UI.escape(parentLabel)}</span>
          <button id="wk-note-close" style="background:none;border:none;cursor:pointer;color:var(--c-text-muted);padding:4px">
            <svg class="ph-icon" aria-hidden="true"><use href="/icons/phosphor.svg#x"></use></svg>
          </button>
        </div>
        <textarea id="wk-note-text" rows="5"
                  style="width:100%;box-sizing:border-box;padding:var(--space-3);
                         border:1.5px solid var(--c-border);border-radius:var(--radius-md);
                         font-size:var(--text-sm);font-family:inherit;
                         background:var(--c-bg);color:var(--c-text);resize:vertical;flex:1"
                  placeholder="Deine Notiz zu diesem Gassi-Treffen…">${UI.escape(existingNote?.text || '')}</textarea>
        <div style="display:flex;gap:var(--space-2);margin-top:var(--space-3)">
          <button id="wk-note-cancel" class="btn btn-secondary flex-1">Abbrechen</button>
          <button id="wk-note-save"   class="btn btn-primary flex-1">Speichern</button>
        </div>
      </div>
    `;
    document.body.appendChild(ovl);

    const close = () => ovl.remove();
    ovl.querySelector('#wk-note-close')?.addEventListener('click', close);
    ovl.querySelector('#wk-note-cancel')?.addEventListener('click', close);
    ovl.addEventListener('click', e => { if (e.target === ovl) close(); });

    ovl.querySelector('#wk-note-save')?.addEventListener('click', async () => {
      const text = ovl.querySelector('#wk-note-text')?.value?.trim() || '';
      const payload = { text, parent_label: parentLabel, location_name: locationName || null };
      try {
        if (existingNote?.id) {
          await API.notes.update(existingNote.id, payload);
        } else {
          await API.notes.create(parentType, String(parentId), payload);
        }
        UI.toast.success('Notiz gespeichert.');
        close();
      } catch (err) { UI.toast.error(err.message || 'Fehler beim Speichern.'); }
    });
  }

  return { init, refresh, onDogChange, openNew, openDetail: _openDetail };

})();
