(function () {
  let active = false;
  let initialized = false;
  const API_URL = window.API_URL || 'https://fb.srv.medeba-media.de/api';
  const BULK_COUNT_STORAGE_KEY = 'dailyBookmarkBulkCount';
  const FILTER_STORAGE_KEY = 'dailyBookmarkFilters';
  const SORT_STORAGE_KEY = 'dailyBookmarkSort';
  const AUTO_OPEN_STORAGE_KEY = 'dailyBookmarkAutoOpen';
  const DEFAULT_BULK_COUNT = 5;
  const DEFAULT_SORT = { column: 'last_completed_at', direction: 'desc' };
  const AUTO_OPEN_DELAY_MS = 1500;
  const LOGIN_PAGE = 'login.html';

  function handleUnauthorized(response) {
    if (response && response.status === 401) {
      if (typeof redirectToLogin === 'function') {
        redirectToLogin();
      } else {
        window.location.href = LOGIN_PAGE;
      }
      return true;
    }
    return false;
  }

  const state = {
    dayKey: formatDayKey(new Date()),
    items: [],
    loading: false,
    saving: false,
    processingBatch: false,
    error: '',
    bulkCount: loadBulkCount(),
    filters: loadFilters(),
    sort: loadSort(),
    importing: false,
    autoOpenEnabled: loadAutoOpenEnabled(),
    autoOpenTriggered: false,
    autoOpenTimerId: null,
    autoOpenCountdownIntervalId: null
  };

  let editingId = null;

  const dailyDayLabel = document.getElementById('dailyDayLabel');
  const dailyDaySubLabel = document.getElementById('dailyDaySubLabel');
  const dailyPrevDayBtn = document.getElementById('dailyPrevDayBtn');
  const dailyNextDayBtn = document.getElementById('dailyNextDayBtn');
  const dailyTodayBtn = document.getElementById('dailyTodayBtn');
  const dailyRefreshBtn = document.getElementById('dailyRefreshBtn');
  const dailyHeroStats = document.getElementById('dailyHeroStats');
  const dailyListSummary = document.getElementById('dailyListSummary');
  const dailyListStatus = document.getElementById('dailyListStatus');
  const dailyTableBody = document.getElementById('dailyTableBody');
  const dailyBulkCountSelect = document.getElementById('dailyBulkCountSelect');
  const dailyBulkOpenBtn = document.getElementById('dailyBulkOpenBtn');
  const dailyAutoOpenToggle = document.getElementById('dailyAutoOpenToggle');
  const dailyAutoOpenOverlay = document.getElementById('dailyAutoOpenOverlay');
  const dailyAutoOpenOverlayPanel = document.getElementById('dailyAutoOpenOverlayPanel');
  const dailyAutoOpenCountdown = document.getElementById('dailyAutoOpenCountdown');
  const dailyOpenCreateBtn = document.getElementById('dailyOpenCreateBtn');

  const modal = document.getElementById('dailyBookmarkModal');
  const dailyModalCloseBtn = document.getElementById('dailyModalCloseBtn');
  const dailyModalBackdrop = modal ? modal.querySelector('.modal__backdrop') : null;
  const formEl = document.getElementById('dailyBookmarkForm');
  const dailyTitleInput = document.getElementById('dailyTitleInput');
  const dailyUrlInput = document.getElementById('dailyUrlInput');
  const dailyNotesInput = document.getElementById('dailyNotesInput');
  const dailyResetBtn = document.getElementById('dailyResetBtn');
  const dailySubmitBtn = document.getElementById('dailySubmitBtn');
  const dailyPreviewLink = document.getElementById('dailyPreviewLink');
  const dailyFormStatus = document.getElementById('dailyFormStatus');
  const dailyFormModeLabel = document.getElementById('dailyFormModeLabel');
  const dailyUrlSuggestionBox = document.getElementById('dailyUrlSuggestionBox');
  const dailyMarkerInput = document.getElementById('dailyMarkerInput');
  const dailyActiveInput = document.getElementById('dailyActiveInput');
  const markerFilterSelect = document.getElementById('dailyMarkerFilter');
  const urlFilterInput = document.getElementById('dailyUrlFilter');
  const dailyResetViewBtn = document.getElementById('dailyResetViewBtn');
  const sortButtons = Array.from(document.querySelectorAll('[data-sort-key]'));
  const dailyOpenImportBtn = document.getElementById('dailyOpenImportBtn');
  const dailyImportModal = document.getElementById('dailyImportModal');
  const dailyImportCloseBtn = document.getElementById('dailyImportCloseBtn');
  const dailyImportBackdrop = dailyImportModal ? dailyImportModal.querySelector('.modal__backdrop') : null;
  const dailyImportForm = document.getElementById('dailyImportForm');
  const dailyImportInput = document.getElementById('dailyImportInput');
  const dailyImportMarkerInput = document.getElementById('dailyImportMarkerInput');
  const dailyImportResetBtn = document.getElementById('dailyImportResetBtn');
  const dailyImportSubmitBtn = document.getElementById('dailyImportSubmitBtn');
  const dailyImportStatus = document.getElementById('dailyImportStatus');

  const PLACEHOLDER_PATTERN = /\{\{\s*([^}]+)\s*\}\}/gi;

  function ensureStyles(enabled) {
    const link = document.getElementById('dailyBookmarksCss');
    if (link) {
      link.disabled = !enabled;
    }
  }

  function formatDayKey(date) {
    const d = date instanceof Date ? date : new Date();
    const year = d.getFullYear();
    const month = String(d.getMonth() + 1).padStart(2, '0');
    const day = String(d.getDate()).padStart(2, '0');
    return `${year}-${month}-${day}`;
  }

  function parseDayKey(dayKey) {
    if (typeof dayKey !== 'string') {
      return new Date();
    }
    const parts = dayKey.split('-').map((part) => parseInt(part, 10));
    if (parts.length !== 3 || parts.some(Number.isNaN)) {
      return new Date();
    }
    return new Date(parts[0], parts[1] - 1, parts[2]);
  }

  function addDays(date, delta) {
    const base = date instanceof Date ? date : new Date();
    const next = new Date(base);
    next.setDate(base.getDate() + delta);
    return next;
  }

  function formatDayLabel(dayKey) {
    const date = parseDayKey(dayKey);
    return date.toLocaleDateString('de-DE', {
      weekday: 'long',
      day: '2-digit',
      month: 'long',
      year: 'numeric'
    });
  }

  function formatRelativeDay(dayKey) {
    const target = parseDayKey(dayKey);
    const today = new Date();
    const todayKey = formatDayKey(today);
    const diff = Math.round((target.setHours(0, 0, 0, 0) - new Date(todayKey).setHours(0, 0, 0, 0)) / 86400000);
    if (diff === 0) return 'Heute';
    if (diff === 1) return 'Morgen';
    if (diff === -1) return 'Gestern';
    if (diff > 1) return `In ${diff} Tagen`;
    return `${Math.abs(diff)} Tage her`;
  }

  function loadBulkCount() {
    try {
      const stored = localStorage.getItem(BULK_COUNT_STORAGE_KEY);
      const value = parseInt(stored, 10);
      if (!Number.isNaN(value) && [1, 5, 10, 15, 20].includes(value)) {
        return value;
      }
    } catch (error) {
      // ignore
    }
    return DEFAULT_BULK_COUNT;
  }

  function persistBulkCount(value) {
    try {
      localStorage.setItem(BULK_COUNT_STORAGE_KEY, String(value));
    } catch (error) {
      // ignore
    }
  }

  function loadFilters() {
    try {
      const raw = localStorage.getItem(FILTER_STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw);
        return {
          marker: typeof parsed.marker === 'string' ? parsed.marker : '',
          url: typeof parsed.url === 'string' ? parsed.url : ''
        };
      }
    } catch (error) {
      // ignore
    }
    return { marker: '', url: '' };
  }

  function persistFilters(filters) {
    try {
      localStorage.setItem(FILTER_STORAGE_KEY, JSON.stringify(filters || {}));
    } catch (error) {
      // ignore
    }
  }

  function loadSort() {
    try {
      const raw = localStorage.getItem(SORT_STORAGE_KEY);
      if (raw) {
        const parsed = JSON.parse(raw);
        const allowedColumns = ['url_template', 'marker', 'created_at', 'updated_at', 'last_completed_at'];
        const allowedDirections = ['asc', 'desc'];
        if (
          parsed &&
          allowedColumns.includes(parsed.column) &&
          allowedDirections.includes(parsed.direction)
        ) {
          return parsed;
        }
      }
    } catch (error) {
      // ignore
    }
    return { ...DEFAULT_SORT };
  }

  function persistSort(sort) {
    try {
      localStorage.setItem(SORT_STORAGE_KEY, JSON.stringify(sort || DEFAULT_SORT));
    } catch (error) {
      // ignore
    }
  }

  function loadAutoOpenEnabled() {
    try {
      return localStorage.getItem(AUTO_OPEN_STORAGE_KEY) === '1';
    } catch (error) {
      return false;
    }
  }

  function persistAutoOpenEnabled(enabled) {
    try {
      localStorage.setItem(AUTO_OPEN_STORAGE_KEY, enabled ? '1' : '0');
    } catch (error) {
      // ignore
    }
  }

  function normalizeItem(item) {
    if (!item || typeof item !== 'object') {
      return null;
    }
    return {
      ...item,
      is_active: Number(item.is_active ?? 1) !== 0
    };
  }

  function resolveTemplate(template, dayKey) {
    if (typeof template !== 'string') {
      return '';
    }
    const baseDate = parseDayKey(dayKey);
    return template.replace(PLACEHOLDER_PATTERN, (_match, contentRaw) => {
      const content = (contentRaw || '').trim();
      if (!content) {
        return '';
      }

      const counterMatch = content.match(/^counter:\s*([+-]?\d+)([+-]\d+)?$/i);
      if (counterMatch) {
        const base = parseInt(counterMatch[1], 10);
        const offset = counterMatch[2] ? parseInt(counterMatch[2], 10) || 0 : 0;
        if (Number.isNaN(base)) {
          return '';
        }
        const date = addDays(baseDate, offset);
        return String(base + date.getDate());
      }

      const placeholderMatch = content.match(/^(date|day|dd|mm|month|yyyy|yy)([+-]\d+)?$/i);
      if (!placeholderMatch) {
        return content;
      }

      const token = String(placeholderMatch[1] || '').toLowerCase();
      const offset = placeholderMatch[2] ? parseInt(placeholderMatch[2], 10) || 0 : 0;
      const date = addDays(baseDate, offset);

      switch (token) {
        case 'date':
          return formatDayKey(date);
        case 'day':
          return String(date.getDate());
        case 'dd':
          return String(date.getDate()).padStart(2, '0');
        case 'month':
        case 'mm':
          return String(date.getMonth() + 1).padStart(2, '0');
        case 'yyyy':
          return String(date.getFullYear());
        case 'yy':
          return String(date.getFullYear()).slice(-2);
        default:
          return token;
      }
    });
  }

  function isDelimiter(char) {
    return !char || /[\\/_\\-\\.\\?#&=]/.test(char);
  }

  function buildUrlSuggestions(urlValue) {
    const suggestions = [];
    if (!urlValue || typeof urlValue !== 'string') {
      return suggestions;
    }

    const raw = urlValue.trim();
    if (!raw) {
      return suggestions;
    }

    const today = parseDayKey(state.dayKey);
    const day = today.getDate();
    const yearFull = String(today.getFullYear());
    const yearShort = yearFull.slice(-2);
    const monthNumber = today.getMonth() + 1;

    const tokens = [];
    const addToken = (text, placeholder) => {
      if (!text) return;
      tokens.push({ text, placeholder });
    };

    const dayText = String(day);
    addToken(dayText, '{{day}}');
    const dayPadded = dayText.padStart(2, '0');
    if (dayPadded !== dayText) {
      addToken(dayPadded, '{{dd}}');
    }

    const monthText = String(monthNumber);
    addToken(monthText, '{{mm}}');
    const monthPadded = monthText.padStart(2, '0');
    if (monthPadded !== monthText) {
      addToken(monthPadded, '{{mm}}');
    }

    addToken(yearFull, '{{yyyy}}');
    addToken(yearShort, '{{yy}}');

    const escapeRegex = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');

    function findOccurrences(text, tokenText) {
      const pattern = new RegExp(`(^|[^0-9])(${escapeRegex(tokenText)})(?=$|[^0-9])`, 'g');
      const occurrences = [];
      let match;
      while ((match = pattern.exec(text)) !== null) {
        const prefixLength = (match[1] || '').length;
        const startIndex = match.index + prefixLength;
        occurrences.push({ index: startIndex, length: tokenText.length });
      }
      return occurrences;
    }

    for (const token of tokens) {
      const occ = findOccurrences(raw, token.text);
      if (!occ.length) {
        continue;
      }
      const candidate = occ[occ.length - 1]; // prefer last occurrence (z.B. am URL-Ende)
      const replaced = `${raw.slice(0, candidate.index)}${token.placeholder}${raw.slice(candidate.index + candidate.length)}`;
      const label = `Ersetze „${token.text}“ durch ${token.placeholder}`;
      if (!suggestions.some((s) => s.label === label && s.value === replaced)) {
        suggestions.push({
          label,
          value: replaced
        });
      }
    }

    return suggestions;
  }

  function renderUrlSuggestions() {
    if (!dailyUrlSuggestionBox) {
      return;
    }
    const suggestions = buildUrlSuggestions(dailyUrlInput ? dailyUrlInput.value : '');
    dailyUrlSuggestionBox.innerHTML = '';
    if (!suggestions.length) {
      dailyUrlSuggestionBox.hidden = true;
      return;
    }

    const text = document.createElement('span');
    text.className = 'suggestion-box__text';
    text.textContent = 'Mögliche Platzhalter:';
    dailyUrlSuggestionBox.appendChild(text);

    const applySuggestion = (value) => {
      if (!dailyUrlInput) {
        return;
      }
      dailyUrlInput.value = value;
      updatePreviewLink();
      renderUrlSuggestions();
      const end = dailyUrlInput.value.length;
      dailyUrlInput.focus();
      try {
        dailyUrlInput.setSelectionRange(end, end);
      } catch (error) {
        // ignore if not supported
      }
    };

    suggestions.forEach((sugg) => {
      const item = document.createElement('div');
      item.className = 'suggestion-box__item';

      const btn = document.createElement('button');
      btn.type = 'button';
      btn.className = 'suggestion-btn';
      btn.textContent = sugg.label;
      btn.addEventListener('click', () => {
        applySuggestion(sugg.value);
      });
      item.appendChild(btn);

      const preview = document.createElement('a');
      preview.className = 'suggestion-preview';
      preview.href = resolveTemplate(sugg.value, state.dayKey) || sugg.value;
      preview.target = '_blank';
      preview.rel = 'noopener';
      preview.title = resolveTemplate(sugg.value, state.dayKey) || sugg.value;
      preview.textContent = resolveTemplate(sugg.value, state.dayKey) || sugg.value;
      preview.addEventListener('click', (event) => {
        event.preventDefault();
        applySuggestion(sugg.value);
      });
      item.appendChild(preview);

      dailyUrlSuggestionBox.appendChild(item);
    });

    dailyUrlSuggestionBox.hidden = false;
  }

  async function apiFetch(url, options = {}) {
    const response = await fetch(url, {
      ...options,
      credentials: 'include',
      headers: {
        'Content-Type': 'application/json',
        ...(options.headers || {})
      }
    });

    if (handleUnauthorized(response)) {
      throw new Error('Nicht angemeldet');
    }

    if (!response.ok) {
      const message = `Fehler: HTTP ${response.status}`;
      throw new Error(message);
    }

    if (response.status === 204) {
      return null;
    }

    const text = await response.text();
    if (!text) {
      return null;
    }

    try {
      return JSON.parse(text);
    } catch (error) {
      return null;
    }
  }

  function updateDayUI() {
    if (dailyDayLabel) {
      dailyDayLabel.textContent = formatDayLabel(state.dayKey);
    }
    if (dailyDaySubLabel) {
      dailyDaySubLabel.textContent = formatRelativeDay(state.dayKey);
    }
    updatePreviewLink();
  }

  function setDayKey(dayKey) {
    state.dayKey = formatDayKey(parseDayKey(dayKey));
    if (!active) return;
    updateDayUI();
    loadDailyBookmarks();
  }

  function setFormStatus(message, isError = false) {
    if (!dailyFormStatus) {
      return;
    }
    dailyFormStatus.textContent = message || '';
    dailyFormStatus.classList.toggle('form-status--error', !!isError);
  }

  function setListStatus(message, isError = false) {
    if (!dailyListStatus) {
      return;
    }
    dailyListStatus.textContent = message || '';
    dailyListStatus.classList.toggle('list-status--error', !!isError);
  }

  function updatePreviewLink() {
    if (!dailyPreviewLink || !dailyUrlInput) {
      return;
    }
    const resolved = resolveTemplate(dailyUrlInput.value || '', state.dayKey);
    dailyPreviewLink.textContent = resolved || '–';
    if (resolved) {
      dailyPreviewLink.href = resolved;
      dailyPreviewLink.target = '_blank';
      dailyPreviewLink.rel = 'noopener';
    } else {
      dailyPreviewLink.removeAttribute('href');
    }
    renderUrlSuggestions();
  }

  function resetForm() {
    editingId = null;
    dailyFormModeLabel.textContent = 'Neues Bookmark';
    dailySubmitBtn.textContent = 'Speichern';
    formEl.reset();
    if (dailyMarkerInput) {
      dailyMarkerInput.value = '';
    }
    if (dailyActiveInput) {
      dailyActiveInput.checked = true;
    }
    setFormStatus('');
    updatePreviewLink();
    renderUrlSuggestions();
  }

  function openModal(mode, bookmark) {
    if (dailyImportModal && !dailyImportModal.hidden) {
      closeImportModal();
    }
    if (mode === 'edit' && bookmark) {
      editingId = bookmark.id;
      dailyFormModeLabel.textContent = 'Bookmark bearbeiten';
      dailySubmitBtn.textContent = 'Aktualisieren';
      dailyTitleInput.value = bookmark.title || '';
      dailyUrlInput.value = bookmark.url_template || '';
      dailyNotesInput.value = bookmark.notes || '';
      if (dailyMarkerInput) {
        dailyMarkerInput.value = bookmark.marker || '';
      }
      if (dailyActiveInput) {
        dailyActiveInput.checked = bookmark.is_active !== false;
      }
      setFormStatus('Bearbeite vorhandenes Bookmark');
    } else {
      resetForm();
    }

    if (modal) {
      modal.hidden = false;
      modal.focus();
    }
    updatePreviewLink();
    if (mode === 'edit' && dailyTitleInput) {
      dailyTitleInput.focus();
    } else if (dailyUrlInput) {
      dailyUrlInput.focus();
    }
  }

  function closeModal() {
    if (modal) {
      modal.hidden = true;
    }
    resetForm();
  }

  function formatRelativeTimestamp(value) {
    if (!value) return 'Noch nie erledigt';
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) {
      return 'Zeitpunkt unbekannt';
    }
    const diffMs = Date.now() - date.getTime();
    const diffMin = Math.floor(diffMs / 60000);
    if (diffMin < 1) return 'Gerade erledigt';
    if (diffMin < 60) return `Vor ${diffMin} Min`;
    const diffHours = Math.floor(diffMin / 60);
    if (diffHours < 24) return `Vor ${diffHours} Std`;
    const diffDays = Math.floor(diffHours / 24);
    return `Vor ${diffDays} Tagen`;
  }

  function formatDateStamp(value) {
    if (!value) return '—';
    const date = new Date(value);
    if (Number.isNaN(date.getTime())) {
      return '—';
    }
    return date.toLocaleString('de-DE', {
      day: '2-digit',
      month: '2-digit',
      year: 'numeric',
      hour: '2-digit',
      minute: '2-digit'
    });
  }

  function normalizeMarkerValue(value) {
    return (value || '').trim();
  }

  function getFilteredItems() {
    const dailyMarkerFilter = state.filters.marker || '';
    const dailyUrlFilter = (state.filters.url || '').toLowerCase();
    return state.items.filter((item) => {
      const currentMarker = normalizeMarkerValue(item.marker).toLowerCase();
      if (dailyMarkerFilter === '__none') {
        if (currentMarker) {
          return false;
        }
      } else if (dailyMarkerFilter) {
        if (currentMarker !== dailyMarkerFilter.toLowerCase()) {
          return false;
        }
      }
      if (dailyUrlFilter) {
        const urlValue = (item.resolved_url || item.url_template || '').toLowerCase();
        if (!urlValue.includes(dailyUrlFilter)) {
          return false;
        }
      }
      return true;
    });
  }

  function sortItems(items) {
    const sorted = [...items];
    const activeSort = state.sort || DEFAULT_SORT;
    const direction = activeSort.direction === 'asc' ? 1 : -1;
    const safeTime = (value) => {
      const time = value ? new Date(value).getTime() : 0;
      return Number.isNaN(time) ? 0 : time;
    };

    sorted.sort((a, b) => {
      switch (activeSort.column) {
        case 'url_template':
          return a.url_template.localeCompare(b.url_template, 'de', { sensitivity: 'base' }) * direction;
        case 'marker':
          return normalizeMarkerValue(a.marker).localeCompare(normalizeMarkerValue(b.marker), 'de', { sensitivity: 'base' }) * direction;
        case 'created_at':
          return (safeTime(a.created_at) - safeTime(b.created_at)) * direction;
        case 'updated_at':
          return (safeTime(a.updated_at) - safeTime(b.updated_at)) * direction;
        case 'last_completed_at':
        default:
          return (safeTime(a.last_completed_at) - safeTime(b.last_completed_at)) * direction;
      }
    });

    return sorted;
  }

  function getVisibleItems() {
    return sortItems(getFilteredItems());
  }

  function updateSortIndicators() {
    if (!sortButtons || !sortButtons.length) {
      return;
    }
    const activeSort = state.sort || DEFAULT_SORT;
    sortButtons.forEach((btn) => {
      const key = btn.dataset.sortKey;
      const isActive = key === activeSort.column;
      btn.classList.toggle('is-active', isActive);
      btn.setAttribute('data-sort-direction', isActive ? (activeSort.direction === 'asc' ? '↑' : '↓') : '↕');
    });
  }

  function renderMarkerFilterOptions() {
    if (!markerFilterSelect) {
      return;
    }
    const activeValue = state.filters.marker || '';
    const markers = Array.from(
      new Set(
        state.items
          .map((item) => normalizeMarkerValue(item.marker))
          .filter(Boolean)
      )
    ).sort((a, b) => a.localeCompare(b, 'de', { sensitivity: 'base' }));

    markerFilterSelect.innerHTML = '';
    const addOption = (value, label) => {
      const opt = document.createElement('option');
      opt.value = value;
      opt.textContent = label;
      markerFilterSelect.appendChild(opt);
    };

    addOption('', 'Alle Marker');
    addOption('__none', 'Ohne Marker');
    markers.forEach((marker) => addOption(marker, marker));

    if (activeValue && activeValue !== '__none' && !markers.includes(activeValue)) {
      addOption(activeValue, `${activeValue} (kein Treffer)`);
    }

    const nextValue = activeValue || '';
    markerFilterSelect.value = nextValue;
    state.filters.marker = nextValue;
    persistFilters(state.filters);
  }

  function renderTable() {
    if (!dailyTableBody) {
      return;
    }

    dailyTableBody.innerHTML = '';
    updateSortIndicators();

    if (state.loading) {
      appendSingleRow('Lade Bookmarks...', 'loading-state');
      return;
    }

    if (state.error) {
      appendSingleRow(state.error, 'error-state');
      return;
    }

    if (!state.items.length) {
      appendSingleRow('Keine Bookmarks vorhanden. Lege dein erstes Bookmark an.', 'empty-state');
      return;
    }

    const visibleItems = getVisibleItems();
    if (!visibleItems.length) {
      appendSingleRow('Keine Bookmarks für diesen Filter.', 'empty-state');
      return;
    }

    visibleItems.forEach((item) => {
      const tr = document.createElement('tr');
      const isActive = item.is_active !== false;
      if (isActive) {
        tr.classList.add(item.completed_for_day ? 'is-done' : 'is-open');
      } else {
        tr.classList.add('is-inactive');
      }

      const urlTd = document.createElement('td');
      urlTd.className = 'url-cell';
      const link = document.createElement('a');
      const resolvedUrl = item.resolved_url || item.url_template;
      link.href = resolvedUrl;
      link.target = '_blank';
      link.rel = 'noopener';
      link.title = resolvedUrl;
      link.textContent = resolvedUrl;
      urlTd.appendChild(link);
      tr.appendChild(urlTd);

      const markerTd = document.createElement('td');
      markerTd.className = 'marker-cell';
      markerTd.textContent = '';
      if (normalizeMarkerValue(item.marker)) {
        const markerChip = document.createElement('span');
        markerChip.className = 'chip chip--marker';
        markerChip.textContent = item.marker;
        markerTd.appendChild(markerChip);
      } else {
        const placeholder = document.createElement('span');
        placeholder.textContent = '–';
        placeholder.classList.add('muted');
        markerTd.appendChild(placeholder);
      }
      if (!isActive) {
        const inactiveChip = document.createElement('span');
        inactiveChip.className = 'chip chip--inactive';
        inactiveChip.textContent = 'Deaktiviert';
        markerTd.appendChild(inactiveChip);
      }
      tr.appendChild(markerTd);

      const createdTd = document.createElement('td');
      createdTd.textContent = formatDateStamp(item.created_at);
      tr.appendChild(createdTd);

      const timeTd = document.createElement('td');
      timeTd.textContent = formatRelativeTimestamp(item.last_completed_at);
      tr.appendChild(timeTd);

      const actionsTd = document.createElement('td');
      actionsTd.className = 'table-actions';

      const openBtn = document.createElement('button');
      openBtn.className = 'ghost-btn';
      openBtn.type = 'button';
      openBtn.textContent = '🔗';
      openBtn.title = isActive ? 'Öffnen' : 'Deaktiviert';
      openBtn.disabled = !isActive;
      openBtn.addEventListener('click', () => {
        const target = item.resolved_url || item.url_template;
        if (!isActive) return;
        if (target) {
          window.open(target, '_blank', 'noopener');
        }
      });
      actionsTd.appendChild(openBtn);

      const toggleBtn = document.createElement('button');
      toggleBtn.className = 'ghost-btn';
      toggleBtn.type = 'button';
      toggleBtn.textContent = item.completed_for_day ? '↩️' : '✅';
      toggleBtn.title = isActive
        ? (item.completed_for_day ? 'Zurücksetzen' : 'Heute erledigt')
        : 'Deaktiviert';
      toggleBtn.disabled = !isActive;
      toggleBtn.addEventListener('click', () => {
        if (item.completed_for_day) {
          undoDailyBookmark(item.id);
        } else {
          completeDailyBookmark(item.id);
        }
      });
      actionsTd.appendChild(toggleBtn);

      const editBtn = document.createElement('button');
      editBtn.className = 'ghost-btn';
      editBtn.type = 'button';
      editBtn.textContent = '✏️';
      editBtn.title = 'Bearbeiten';
      editBtn.addEventListener('click', () => openModal('edit', item));
      actionsTd.appendChild(editBtn);

      const deleteBtn = document.createElement('button');
      deleteBtn.className = 'ghost-btn danger';
      deleteBtn.type = 'button';
      deleteBtn.textContent = '🗑️';
      deleteBtn.title = 'Löschen';
      deleteBtn.addEventListener('click', () => {
        if (window.confirm('Bookmark wirklich löschen?')) {
          deleteDailyBookmark(item.id);
        }
      });
      actionsTd.appendChild(deleteBtn);

      tr.appendChild(actionsTd);
      dailyTableBody.appendChild(tr);
    });
  }

  function appendSingleRow(text, className) {
    const tr = document.createElement('tr');
    const td = document.createElement('td');
    td.colSpan = 5;
    td.className = className;
    td.textContent = text;
    tr.appendChild(td);
    dailyTableBody.appendChild(tr);
  }

  function updateHeroStats() {
    const activeItems = state.items.filter((item) => item.is_active !== false);
    const totalActive = activeItems.length;
    const inactiveCount = state.items.length - totalActive;
    const done = activeItems.filter((item) => item.completed_for_day).length;
    const visibleItems = getFilteredItems().filter((item) => item.is_active !== false);
    const visibleDone = visibleItems.filter((item) => item.completed_for_day).length;
    const filterSuffix = visibleItems.length !== totalActive ? ` · Gefiltert: ${visibleDone}/${visibleItems.length}` : '';
    const inactiveSuffix = inactiveCount ? ` · ${inactiveCount} deaktiviert` : '';
    const baseText = totalActive ? `${done}/${totalActive} erledigt${filterSuffix}` : 'Keine aktiven Bookmarks';
    const text = `${baseText}${inactiveSuffix}`;
    const filterParts = [];
    if (state.filters.marker) {
      filterParts.push(state.filters.marker === '__none' ? 'ohne Marker' : `Marker: ${state.filters.marker}`);
    }
    if (state.filters.url) {
      filterParts.push(`URL enthält „${state.filters.url}“`);
    }
    const filterText = filterParts.length ? ` · Filter: ${filterParts.join(' · ')}` : '';
    if (dailyHeroStats) {
      dailyHeroStats.textContent = `${text}${filterText}`;
    }
    if (dailyListSummary) {
      dailyListSummary.textContent = `${text} – Tag ${state.dayKey}${filterText}`;
    }
  }

  function clearAutoOpenCountdown() {
    if (state.autoOpenCountdownIntervalId) {
      clearInterval(state.autoOpenCountdownIntervalId);
      state.autoOpenCountdownIntervalId = null;
    }
  }

  function updateAutoOpenCountdownLabel(remainingMs) {
    if (!dailyAutoOpenCountdown) return;
    const safeMs = Math.max(0, remainingMs);
    const seconds = safeMs / 1000;
    const formatted = seconds >= 10 ? seconds.toFixed(0) : seconds.toFixed(1);
    dailyAutoOpenCountdown.textContent = formatted;
  }

  function hideAutoOpenOverlay() {
    clearAutoOpenCountdown();
    if (dailyAutoOpenOverlay) {
      dailyAutoOpenOverlay.classList.remove('visible');
      dailyAutoOpenOverlay.hidden = true;
    }
  }

  function showAutoOpenOverlay(delayMs) {
    if (!dailyAutoOpenOverlay) return;
    const duration = Math.max(0, delayMs);
    hideAutoOpenOverlay();
    dailyAutoOpenOverlay.hidden = false;
    requestAnimationFrame(() => dailyAutoOpenOverlay.classList.add('visible'));
    updateAutoOpenCountdownLabel(duration);
    const start = Date.now();
    state.autoOpenCountdownIntervalId = setInterval(() => {
      const remaining = Math.max(0, duration - (Date.now() - start));
      updateAutoOpenCountdownLabel(remaining);
      if (remaining <= 0) {
        clearAutoOpenCountdown();
      }
    }, 100);
  }

  function cancelAutoOpen(showMessage = false) {
    if (state.autoOpenTimerId) {
      clearTimeout(state.autoOpenTimerId);
      state.autoOpenTimerId = null;
    }
    state.autoOpenTriggered = false;
    hideAutoOpenOverlay();
    if (showMessage) {
      setListStatus('Automatisches Öffnen abgebrochen.', false);
    }
  }

  function maybeAutoOpen(reason = '', delayMs = AUTO_OPEN_DELAY_MS) {
    if (!active) {
      hideAutoOpenOverlay();
      return;
    }
    if (!state.autoOpenEnabled) {
      hideAutoOpenOverlay();
      return;
    }
    if (state.processingBatch) return;
    if (state.autoOpenTriggered) return;
    const undone = getVisibleItems().filter(
      (item) => item.is_active !== false && !item.completed_for_day
    );
    if (!undone.length) {
      hideAutoOpenOverlay();
      return;
    }
    if (state.autoOpenTimerId) {
      clearTimeout(state.autoOpenTimerId);
      state.autoOpenTimerId = null;
    }
    hideAutoOpenOverlay();
    state.autoOpenTriggered = true;
    const delay = typeof delayMs === 'number' ? Math.max(0, delayMs) : AUTO_OPEN_DELAY_MS;
    if (delay === 0) {
      if (state.autoOpenEnabled) {
        openBatch({ auto: true });
      } else {
        state.autoOpenTriggered = false;
      }
      return;
    }
    showAutoOpenOverlay(delay);
    state.autoOpenTimerId = setTimeout(() => {
      state.autoOpenTimerId = null;
      hideAutoOpenOverlay();
      if (state.autoOpenEnabled) {
        openBatch({ auto: true });
      } else {
        state.autoOpenTriggered = false;
      }
    }, delay);
  }

  async function loadDailyBookmarks() {
    if (!active) return;
    state.loading = true;
    if (state.autoOpenTimerId) {
      clearTimeout(state.autoOpenTimerId);
      state.autoOpenTimerId = null;
    }
    hideAutoOpenOverlay();
    state.autoOpenTriggered = false;
    state.error = '';
    setListStatus('');
    renderTable();
    try {
      const data = await apiFetch(`${API_URL}/daily-bookmarks?day=${encodeURIComponent(state.dayKey)}`);
      const rows = Array.isArray(data) ? data : [];
      state.items = rows.map((item) => normalizeItem(item)).filter(Boolean);
      state.loading = false;
      updateHeroStats();
      renderMarkerFilterOptions();
      renderTable();
      maybeAutoOpen('load');
    } catch (error) {
      state.loading = false;
      state.error = 'Konnte Bookmarks nicht laden.';
      setListStatus(state.error, true);
      renderTable();
    }
  }

  async function completeDailyBookmark(id) {
    if (!id) return;
    const target = state.items.find((item) => item.id === id);
    if (target && target.is_active === false) {
      setListStatus('Bookmark ist deaktiviert.', true);
      return;
    }
    state.error = '';
    try {
      const updated = await apiFetch(`${API_URL}/daily-bookmarks/${encodeURIComponent(id)}/check`, {
        method: 'POST',
        body: JSON.stringify({ day: state.dayKey })
      });
      const normalized = normalizeItem(updated);
      state.items = state.items.map((item) => (item.id === id ? normalized || item : item));
      updateHeroStats();
      renderTable();
    } catch (error) {
      state.error = 'Konnte nicht abhaken.';
      setListStatus(state.error, true);
      renderTable();
    }
  }

  async function undoDailyBookmark(id) {
    if (!id) return;
    const target = state.items.find((item) => item.id === id);
    if (target && target.is_active === false) {
      setListStatus('Bookmark ist deaktiviert.', true);
      return;
    }
    state.error = '';
    try {
      const updated = await apiFetch(`${API_URL}/daily-bookmarks/${encodeURIComponent(id)}/check?day=${encodeURIComponent(state.dayKey)}`, {
        method: 'DELETE'
      });
      const normalized = normalizeItem(updated);
      state.items = state.items.map((item) => (item.id === id ? normalized || item : item));
      updateHeroStats();
      renderTable();
    } catch (error) {
      state.error = 'Konnte nicht zurücksetzen.';
      setListStatus(state.error, true);
      renderTable();
    }
  }

  async function deleteDailyBookmark(id) {
    if (!id) return;
    state.error = '';
    try {
      await apiFetch(`${API_URL}/daily-bookmarks/${encodeURIComponent(id)}`, {
        method: 'DELETE'
      });
      state.items = state.items.filter((item) => item.id !== id);
      if (editingId === id) {
        resetForm();
      }
      updateHeroStats();
      renderMarkerFilterOptions();
      renderTable();
    } catch (error) {
      state.error = 'Konnte Bookmark nicht löschen.';
      setListStatus(state.error, true);
      renderTable();
    }
  }

  async function submitForm(event) {
    event.preventDefault();
    if (state.saving) return;

    const title = dailyTitleInput.value.trim();
    const url = dailyUrlInput.value.trim();
    const notes = dailyNotesInput.value.trim();
    const marker = dailyMarkerInput ? dailyMarkerInput.value.trim() : '';

    if (!url) {
      setFormStatus('URL-Template ist Pflicht.', true);
      dailyUrlInput.focus();
      return;
    }

    state.saving = true;
    dailySubmitBtn.disabled = true;
    setFormStatus('');

    const payload = {
      title,
      url_template: url,
      notes,
      marker,
      is_active: dailyActiveInput ? dailyActiveInput.checked : true,
      day: state.dayKey
    };

    const targetUrl = editingId
      ? `${API_URL}/daily-bookmarks/${encodeURIComponent(editingId)}`
      : `${API_URL}/daily-bookmarks`;
    const method = editingId ? 'PUT' : 'POST';

    try {
      const saved = await apiFetch(targetUrl, {
        method,
        body: JSON.stringify(payload)
      });
      const normalized = normalizeItem(saved);
      if (editingId) {
        state.items = state.items.map((item) => (item.id === editingId ? normalized || item : item));
      } else if (normalized) {
        state.items = [normalized, ...state.items];
      }
      updateHeroStats();
      renderMarkerFilterOptions();
      renderTable();
      closeModal();
    } catch (error) {
      setFormStatus('Speichern fehlgeschlagen.', true);
    } finally {
      state.saving = false;
      dailySubmitBtn.disabled = false;
    }
  }

  async function openBatch({ auto = false } = {}) {
    if (state.processingBatch) return;
    if (!auto) {
      cancelAutoOpen(false);
    }
    const undone = getVisibleItems().filter(
      (item) => item.is_active !== false && !item.completed_for_day
    );
    if (!undone.length) {
      if (!auto) {
        setListStatus('Keine offenen Bookmarks für den gewählten Tag.', true);
      }
      return;
    }

    const count = state.bulkCount || DEFAULT_BULK_COUNT;
    const selection = undone.slice(0, count);

    state.processingBatch = true;
    if (dailyBulkOpenBtn) {
      dailyBulkOpenBtn.disabled = true;
    }
    if (!auto) {
      setListStatus('');
    } else {
      setListStatus(`Öffne automatisch ${selection.length} Links...`, false);
    }

    for (const item of selection) {
      const target = item.resolved_url || item.url_template;
      if (target) {
        window.open(target, '_blank', 'noopener');
      }
      try {
        const updated = await apiFetch(`${API_URL}/daily-bookmarks/${encodeURIComponent(item.id)}/check`, {
          method: 'POST',
          body: JSON.stringify({ day: state.dayKey })
        });
        const normalized = normalizeItem(updated);
        state.items = state.items.map((entry) => (entry.id === item.id ? normalized || entry : entry));
      } catch (error) {
        setListStatus('Einige Bookmarks konnten nicht abgehakt werden.', true);
      }
    }

    state.processingBatch = false;
    if (dailyBulkOpenBtn) {
      dailyBulkOpenBtn.disabled = false;
    }
    if (auto) {
      setListStatus('');
    }
    updateHeroStats();
    renderTable();
  }

  function setImportStatus(message, isError = false) {
    if (!dailyImportStatus) {
      return;
    }
    dailyImportStatus.textContent = message || '';
    dailyImportStatus.classList.toggle('form-status--error', !!isError);
  }

  function resetImportForm() {
    if (dailyImportForm) {
      dailyImportForm.reset();
    }
    const suggestedMarker = state.filters.marker && state.filters.marker !== '__none' ? state.filters.marker : '';
    if (dailyImportMarkerInput) {
      dailyImportMarkerInput.value = suggestedMarker;
    }
    setImportStatus('');
  }

  function openImportModal() {
    if (modal && !modal.hidden) {
      closeModal();
    }
    resetImportForm();
    if (dailyImportModal) {
      dailyImportModal.hidden = false;
      dailyImportModal.focus();
    }
    if (dailyImportInput) {
      dailyImportInput.focus();
    }
  }

  function closeImportModal() {
    if (dailyImportModal) {
      dailyImportModal.hidden = true;
    }
    resetImportForm();
  }

  async function submitImportForm(event) {
    event.preventDefault();
    if (state.importing) return;

    const rawText = dailyImportInput ? dailyImportInput.value.trim() : '';
    const marker = dailyImportMarkerInput ? dailyImportMarkerInput.value.trim() : '';
    if (!rawText) {
      setImportStatus('Bitte füge mindestens eine URL ein.', true);
      if (dailyImportInput) {
        dailyImportInput.focus();
      }
      return;
    }

    const urls = rawText
      .split(/\r?\n/)
      .map((line) => line.trim())
      .filter(Boolean);

    if (!urls.length) {
      setImportStatus('Keine gültigen Zeilen gefunden.', true);
      return;
    }

    state.importing = true;
    if (dailyImportSubmitBtn) {
      dailyImportSubmitBtn.disabled = true;
    }
    setImportStatus('Import läuft...');

    try {
      const result = await apiFetch(`${API_URL}/daily-bookmarks/import`, {
        method: 'POST',
        body: JSON.stringify({ urls, marker, day: state.dayKey })
      });

      const importedItemsRaw = Array.isArray(result && result.items) ? result.items : [];
      const importedItems = importedItemsRaw.map((item) => normalizeItem(item)).filter(Boolean);
      const importedIds = new Set(importedItems.map((entry) => entry.id));
      const remaining = state.items.filter((item) => !importedIds.has(item.id));
      state.items = [...importedItems, ...remaining];

      const summaryParts = [];
      const createdCount = result && typeof result.created === 'number' ? result.created : importedItems.length;
      summaryParts.push(`${createdCount} neu`);
      if (result && result.skipped_existing) summaryParts.push(`${result.skipped_existing} bereits vorhanden`);
      if (result && result.skipped_invalid) summaryParts.push(`${result.skipped_invalid} ungültig`);
      if (result && result.skipped_duplicates) summaryParts.push(`${result.skipped_duplicates} Duplikate`);

      setListStatus(`Import fertig: ${summaryParts.join(' · ')}`);
      updateHeroStats();
      renderMarkerFilterOptions();
      renderTable();
      closeImportModal();
    } catch (error) {
      setImportStatus(error && error.message ? error.message : 'Import fehlgeschlagen.', true);
    } finally {
      state.importing = false;
      if (dailyImportSubmitBtn) {
        dailyImportSubmitBtn.disabled = false;
      }
    }
  }

  function setupEvents() {
    if (dailyPrevDayBtn) {
      dailyPrevDayBtn.addEventListener('click', () => setDayKey(formatDayKey(addDays(parseDayKey(state.dayKey), -1))));
    }
    if (dailyNextDayBtn) {
      dailyNextDayBtn.addEventListener('click', () => setDayKey(formatDayKey(addDays(parseDayKey(state.dayKey), 1))));
    }
    if (dailyTodayBtn) {
      dailyTodayBtn.addEventListener('click', () => setDayKey(formatDayKey(new Date())));
    }
    if (dailyRefreshBtn) {
      dailyRefreshBtn.addEventListener('click', () => loadDailyBookmarks());
    }
    if (dailyOpenCreateBtn) {
      dailyOpenCreateBtn.addEventListener('click', () => openModal('create'));
    }
    if (dailyModalCloseBtn) {
      dailyModalCloseBtn.addEventListener('click', closeModal);
    }
    if (modal) {
      modal.addEventListener('click', (event) => {
        if (event.target === modal) {
          closeModal();
        }
      });
    }
    if (dailyModalBackdrop) {
      dailyModalBackdrop.addEventListener('click', closeModal);
    }
    document.addEventListener('keydown', (event) => {
      if (!active) return;
      if (event.key === 'Escape') {
        if (modal && !modal.hidden) {
          closeModal();
        }
        if (dailyImportModal && !dailyImportModal.hidden) {
          closeImportModal();
        }
      }
    });
    if (dailyUrlInput) {
      dailyUrlInput.addEventListener('input', updatePreviewLink);
      dailyUrlInput.addEventListener('blur', renderUrlSuggestions);
    }
    if (formEl) {
      formEl.addEventListener('submit', submitForm);
    }
    if (dailyResetBtn) {
      dailyResetBtn.addEventListener('click', resetForm);
    }
    if (dailyBulkCountSelect) {
      dailyBulkCountSelect.value = String(state.bulkCount);
      dailyBulkCountSelect.addEventListener('change', () => {
        const value = parseInt(dailyBulkCountSelect.value, 10);
        if (!Number.isNaN(value)) {
          state.bulkCount = value;
          persistBulkCount(value);
        }
      });
    }
    if (dailyBulkOpenBtn) {
      dailyBulkOpenBtn.addEventListener('click', () => openBatch());
    }
    if (dailyAutoOpenOverlayPanel) {
      dailyAutoOpenOverlayPanel.addEventListener('click', () => cancelAutoOpen(true));
    }
    if (dailyAutoOpenToggle) {
      dailyAutoOpenToggle.checked = !!state.autoOpenEnabled;
      dailyAutoOpenToggle.addEventListener('change', () => {
        state.autoOpenEnabled = dailyAutoOpenToggle.checked;
        persistAutoOpenEnabled(state.autoOpenEnabled);
        state.autoOpenTriggered = false;
        if (!state.autoOpenEnabled && state.autoOpenTimerId) {
          cancelAutoOpen(false);
        }
        if (state.autoOpenEnabled) {
          maybeAutoOpen('toggle');
        } else {
          hideAutoOpenOverlay();
        }
      });
    }
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'visible' && state.autoOpenEnabled) {
        // Reset the guard so that returning to the tab can trigger the next batch.
        if (state.autoOpenTimerId) {
          clearTimeout(state.autoOpenTimerId);
          state.autoOpenTimerId = null;
        }
        state.autoOpenTriggered = false;
        maybeAutoOpen('visibility', AUTO_OPEN_DELAY_MS);
      }
    });
    if (markerFilterSelect) {
      markerFilterSelect.addEventListener('change', () => {
        state.filters.marker = markerFilterSelect.value || '';
        persistFilters(state.filters);
        updateHeroStats();
        renderTable();
      });
    }
    if (urlFilterInput) {
      urlFilterInput.value = state.filters.url || '';
      urlFilterInput.addEventListener('input', () => {
        state.filters.url = urlFilterInput.value.trim();
        persistFilters(state.filters);
        updateHeroStats();
        renderTable();
      });
    }
    if (dailyResetViewBtn) {
      dailyResetViewBtn.addEventListener('click', () => {
        state.filters = { marker: '', url: '' };
        state.sort = { ...DEFAULT_SORT };
        persistFilters(state.filters);
        persistSort(state.sort);
        renderMarkerFilterOptions();
        if (urlFilterInput) {
          urlFilterInput.value = '';
        }
        updateHeroStats();
        renderTable();
      });
    }
    if (sortButtons && sortButtons.length) {
      sortButtons.forEach((btn) => {
        btn.addEventListener('click', () => {
          const key = btn.dataset.sortKey;
          if (!key) return;
          if (state.sort.column === key) {
            state.sort.direction = state.sort.direction === 'asc' ? 'desc' : 'asc';
          } else {
            const defaultDirection = ['last_completed_at', 'updated_at', 'created_at'].includes(key) ? 'desc' : 'asc';
            state.sort = { column: key, direction: defaultDirection };
          }
          persistSort(state.sort);
          renderTable();
        });
      });
    }
    if (dailyOpenImportBtn) {
      dailyOpenImportBtn.addEventListener('click', openImportModal);
    }
    if (dailyImportCloseBtn) {
      dailyImportCloseBtn.addEventListener('click', closeImportModal);
    }
    if (dailyImportModal) {
      dailyImportModal.addEventListener('click', (event) => {
        if (event.target === dailyImportModal) {
          closeImportModal();
        }
      });
    }
    if (dailyImportBackdrop) {
      dailyImportBackdrop.addEventListener('click', closeImportModal);
    }
    if (dailyImportForm) {
      dailyImportForm.addEventListener('submit', submitImportForm);
    }
    if (dailyImportResetBtn) {
      dailyImportResetBtn.addEventListener('click', resetImportForm);
    }
  }

  function init() {
    if (initialized) return;
    setupEvents();
    initialized = true;
  }

  function cleanup() {
    active = false;
    cancelAutoOpen(false);
    ensureStyles(false);
    hideAutoOpenOverlay();
  }

  function activate() {
    ensureStyles(true);
    init();
    active = true;
    updateDayUI();
    updatePreviewLink();
    loadDailyBookmarks();
  }

  window.DailyBookmarksPage = {
    activate,
    deactivate: cleanup
  };

  const dailySection = document.querySelector('[data-view="daily-bookmarks"]');
  if (dailySection && dailySection.classList.contains('app-view--active')) {
    activate();
  }
})();
