import assert from 'node:assert/strict';
import fs from 'node:fs/promises';
import path from 'node:path';
import test from 'node:test';
import vm from 'node:vm';

const root = path.resolve(import.meta.dirname, '..');

class MemoryStorage {
  constructor() {
    this.values = new Map();
  }

  getItem(key) {
    return this.values.has(key) ? this.values.get(key) : null;
  }

  setItem(key, value) {
    this.values.set(key, String(value));
  }

  removeItem(key) {
    this.values.delete(key);
  }
}

async function loadModule() {
  const source = await fs.readFile(path.join(root, 'public/js/privacy-storage.js'), 'utf8');
  const localStorage = new MemoryStorage();
  const context = {
    Wegwichtel: {},
    localStorage,
    document: { cookie: '' },
    Date,
    JSON,
    Number,
    Set,
    String,
    Promise,
    setTimeout,
    clearTimeout
  };
  context.globalThis = context;
  vm.runInNewContext(source, context, { filename: path.join(root, 'public/js/privacy-storage.js') });
  return { storage: context.Wegwichtel.PrivacyStorage, localStorage };
}

test('route progress storage is opt-in and deleting the option removes progress data', async () => {
  const { storage, localStorage } = await loadModule();
  assert.equal(storage.isProgressStorageEnabled(), false);
  assert.equal(storage.activateRoute({ id: 7, name: 'Testweg' }), null);

  storage.setProgressStorageEnabled(true);
  storage.activateRoute({ id: 7, name: 'Testweg' });
  storage.markVisited(7, 11);
  storage.markViewed(7, 12);
  storage.markAudioPlayed(7, 12);
  storage.saveRouteState({ id: 7, name: 'Testweg' }, 'paused', 23, [11], [12], [12]);

  const route = storage.loadRoute(7);
  assert.equal(route.routeState, 'paused');
  assert.equal(route.routeProgressIndex, 23);
  assert.deepEqual([...route.visitedPoiIds], [11]);
  assert.deepEqual([...route.viewedPoiIds], [12]);
  assert.deepEqual([...route.playedAudioPoiIds], [12]);

  storage.setProgressStorageEnabled(false);
  assert.equal(storage.isProgressStorageEnabled(), false);
  assert.equal(localStorage.getItem(storage.PROGRESS_KEY), null);
});

test('route progress older than 24 hours is removed with visible loop progress', async () => {
  const { storage, localStorage } = await loadModule();
  storage.setProgressStorageEnabled(true);

  const oldTimestamp = new Date(Date.now() - storage.MAX_PROGRESS_AGE_MS - 1000).toISOString();
  const freshTimestamp = new Date().toISOString();
  localStorage.setItem(storage.PROGRESS_KEY, JSON.stringify({
    version: 1,
    currentRouteId: 1,
    routes: {
      1: { routeId: 1, routeName: 'Alt', updatedAt: oldTimestamp },
      2: { routeId: 2, routeName: 'Neu', updatedAt: freshTimestamp }
    }
  }));

  const updates = [];
  const result = await storage.cleanupExpired((removed, total) => updates.push(`${removed} / ${total}`));
  assert.equal(result.removed, 1);
  assert.equal(result.total, 1);
  assert.deepEqual(updates, ['0 / 1', '1 / 1']);
  assert.equal(storage.loadRoute(1), null);
  assert.equal(storage.loadRoute(2).routeName, 'Neu');
});
