(function (ns) {
  'use strict';

  const SETTINGS_KEY = 'wegwichtel.privacy.v1';
  const PROGRESS_KEY = 'wegwichtel.route-progress.v1';
  const COOKIE_PREFIX = 'wegwichtel_';
  const MAX_PROGRESS_AGE_MS = 24 * 60 * 60 * 1000;
  const STORE_VERSION = 1;

  function storage() {
    try {
      return globalThis.localStorage ?? null;
    } catch {
      return null;
    }
  }

  function nowIso() {
    return new Date().toISOString();
  }

  function readJson(key, fallback) {
    const backend = storage();
    if (!backend) return fallback;

    try {
      const raw = backend.getItem(key);
      return raw ? JSON.parse(raw) : fallback;
    } catch {
      return fallback;
    }
  }

  function writeJson(key, value) {
    const backend = storage();
    if (!backend) return false;

    try {
      backend.setItem(key, JSON.stringify(value));
      return true;
    } catch {
      return false;
    }
  }

  function removeItem(key) {
    const backend = storage();
    if (!backend) return;

    try {
      backend.removeItem(key);
    } catch {
      // Private browsing modes may reject storage access. The app remains usable without persistence.
    }
  }

  function defaultSettings() {
    return { progressStorage: false, updatedAt: null };
  }

  function settings() {
    const value = readJson(SETTINGS_KEY, defaultSettings());
    return {
      progressStorage: value?.progressStorage === true,
      updatedAt: typeof value?.updatedAt === 'string' ? value.updatedAt : null
    };
  }

  function saveSettings(progressStorage) {
    return writeJson(SETTINGS_KEY, {
      progressStorage: progressStorage === true,
      updatedAt: nowIso()
    });
  }

  function defaultProgressStore() {
    return { version: STORE_VERSION, currentRouteId: null, routes: {} };
  }

  function progressStore() {
    const value = readJson(PROGRESS_KEY, defaultProgressStore());
    if (value?.version !== STORE_VERSION || typeof value?.routes !== 'object' || value.routes === null) {
      return defaultProgressStore();
    }

    return {
      version: STORE_VERSION,
      currentRouteId: value.currentRouteId ?? null,
      routes: value.routes
    };
  }

  function persistProgressStore(value) {
    if (!settings().progressStorage) return false;
    return writeJson(PROGRESS_KEY, value);
  }

  function uniqueIds(values) {
    return [...new Set((Array.isArray(values) ? values : [])
      .map(value => Number(value))
      .filter(Number.isFinite))];
  }

  function routeRecord(route, previous = {}) {
    const timestamp = nowIso();
    return {
      routeId: route.id,
      routeName: String(route.name ?? previous.routeName ?? ''),
      routeState: previous.routeState ?? 'idle',
      routeProgressIndex: Number.isInteger(previous.routeProgressIndex)
        ? previous.routeProgressIndex
        : null,
      visitedPoiIds: uniqueIds(previous.visitedPoiIds),
      viewedPoiIds: uniqueIds(previous.viewedPoiIds),
      playedAudioPoiIds: uniqueIds(previous.playedAudioPoiIds),
      startedAt: previous.startedAt ?? timestamp,
      updatedAt: timestamp
    };
  }

  function updateRoute(routeId, updater) {
    if (!settings().progressStorage || routeId == null) return null;

    const store = progressStore();
    const key = String(routeId);
    const current = store.routes[key];
    if (!current) return null;

    const updated = updater({ ...current });
    updated.updatedAt = nowIso();
    store.currentRouteId = routeId;
    store.routes[key] = updated;
    persistProgressStore(store);
    return updated;
  }

  function markPoi(routeId, field, poiId) {
    const normalizedId = Number(poiId);
    if (!Number.isFinite(normalizedId)) return null;

    return updateRoute(routeId, record => {
      record[field] = uniqueIds([...(record[field] ?? []), normalizedId]);
      return record;
    });
  }

  function clearApplicationCookies() {
    const cookieText = globalThis.document?.cookie;
    if (!cookieText) return;

    cookieText.split(';').forEach(item => {
      const name = item.split('=', 1)[0].trim();
      if (!name.startsWith(COOKIE_PREFIX)) return;
      globalThis.document.cookie = `${name}=; Max-Age=0; Path=/; SameSite=Lax`;
    });
  }

  function setProgressStorageEnabled(enabled) {
    const active = enabled === true;
    const saved = saveSettings(active);
    if (!active) removeItem(PROGRESS_KEY);
    return saved && settings().progressStorage;
  }

  function activateRoute(route) {
    if (!settings().progressStorage || route?.id == null) return null;

    const store = progressStore();
    const key = String(route.id);
    const record = routeRecord(route, store.routes[key]);
    store.currentRouteId = route.id;
    store.routes[key] = record;
    persistProgressStore(store);
    return record;
  }

  function saveRouteState(route, routeState, routeProgressIndex, visitedPoiIds, viewedPoiIds, playedAudioPoiIds) {
    if (route?.id == null) return null;

    return updateRoute(route.id, record => ({
      ...record,
      routeName: String(route.name ?? record.routeName ?? ''),
      routeState: String(routeState ?? 'idle'),
      routeProgressIndex: Number.isInteger(routeProgressIndex) ? routeProgressIndex : null,
      visitedPoiIds: uniqueIds(visitedPoiIds),
      viewedPoiIds: uniqueIds(viewedPoiIds),
      playedAudioPoiIds: uniqueIds(playedAudioPoiIds)
    }));
  }

  function loadRoute(routeId) {
    if (!settings().progressStorage || routeId == null) return null;
    return progressStore().routes[String(routeId)] ?? null;
  }

  function nextTurn() {
    return new Promise(resolve => globalThis.setTimeout(resolve, 0));
  }

  async function cleanupExpired(onProgress = () => {}) {
    if (!settings().progressStorage) {
      removeItem(PROGRESS_KEY);
      return { removed: 0, total: 0 };
    }

    const store = progressStore();
    const cutoff = Date.now() - MAX_PROGRESS_AGE_MS;
    const expiredKeys = Object.entries(store.routes)
      .filter(([, route]) => {
        const timestamp = Date.parse(route?.updatedAt ?? '');
        return !Number.isFinite(timestamp) || timestamp <= cutoff;
      })
      .map(([key]) => key);

    if (!expiredKeys.length) return { removed: 0, total: 0 };

    let removed = 0;
    onProgress(removed, expiredKeys.length);

    for (const key of expiredKeys) {
      delete store.routes[key];
      if (String(store.currentRouteId) === key) store.currentRouteId = null;
      removed += 1;
      persistProgressStore(store);
      onProgress(removed, expiredKeys.length);
      await nextTurn();
    }

    return { removed, total: expiredKeys.length };
  }

  clearApplicationCookies();

  ns.PrivacyStorage = Object.freeze({
    SETTINGS_KEY,
    PROGRESS_KEY,
    MAX_PROGRESS_AGE_MS,
    cookiesEnabled: () => false,
    clearApplicationCookies,
    isProgressStorageEnabled: () => settings().progressStorage,
    setProgressStorageEnabled,
    cleanupExpired,
    activateRoute,
    loadRoute,
    saveRouteState,
    markVisited: (routeId, poiId) => markPoi(routeId, 'visitedPoiIds', poiId),
    markViewed: (routeId, poiId) => markPoi(routeId, 'viewedPoiIds', poiId),
    markAudioPlayed: (routeId, poiId) => markPoi(routeId, 'playedAudioPoiIds', poiId),
    clearProgress: () => removeItem(PROGRESS_KEY)
  });
}(globalThis.Wegwichtel ??= {}));
