const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');

const source = fs.readFileSync('sidepanel/contribution-content-update-service.js', 'utf8');

function createContributionContentService(options = {}) {
  const cache = new Map();
  const windowObject = {};
  let fetchCalls = 0;

  const localStorage = {
    getItem(key) {
      return cache.has(key) ? cache.get(key) : null;
    },
    setItem(key, value) {
      cache.set(key, String(value));
    },
    removeItem(key) {
      cache.delete(key);
    },
  };

  if (options.cachedSnapshot) {
    cache.set(
      'multipage-contribution-content-summary-v1',
      JSON.stringify(options.cachedSnapshot)
    );
  }

  const fetchImpl = options.fetchImpl || (async () => ({
    ok: true,
    async json() {
      return {
        ok: true,
        items: [],
        prompt_version: '',
        has_visible_updates: false,
        latest_updated_at: '',
        latest_updated_at_display: '',
      };
    },
  }));

  const wrappedFetch = async (...args) => {
    fetchCalls += 1;
    return fetchImpl(...args);
  };

  const api = new Function(
    'window',
    'localStorage',
    'fetch',
    'AbortController',
    'setTimeout',
    'clearTimeout',
    `${source}; return window.SidepanelContributionContentService;`
  )(
    windowObject,
    localStorage,
    wrappedFetch,
    AbortController,
    setTimeout,
    clearTimeout
  );

  return {
    api,
    getFetchCalls() {
      return fetchCalls;
    },
  };
}

test('getContentUpdateSnapshot returns a prompt version for visible contribution content updates', async () => {
  const { api } = createContributionContentService({
    fetchImpl: async () => ({
      ok: true,
      async json() {
        return {
          ok: true,
          prompt_version: 'auto_run_notice:2026-04-21T12:05:00Z',
          has_visible_updates: true,
          latest_updated_at: '2026-04-21T12:05:00Z',
          latest_updated_at_display: '2026-04-21 20:05',
          items: [
            {
              slug: 'auto_run_notice',
              title: '自动提示',
              text: '公告和使用教程更新了，可点上方“贡献/使用教程”查看。',
              is_enabled: true,
              has_content: true,
              is_visible: true,
              updated_at: '2026-04-21T12:05:00Z',
              updated_at_display: '2026-04-21 20:05',
            },
          ],
        };
      },
    }),
  });

  const snapshot = await api.getContentUpdateSnapshot();

  assert.equal(snapshot.status, 'update-available');
  assert.equal(snapshot.promptVersion, 'auto_run_notice:2026-04-21T12:05:00Z');
  assert.equal(snapshot.hasVisibleUpdates, true);
  assert.equal(snapshot.latestUpdatedAt, '2026-04-21T12:05:00Z');
  assert.equal(snapshot.items.length, 1);
  assert.deepEqual(
    snapshot.items.map((item) => [item.slug, item.isVisible, item.text]),
    [['auto_run_notice', true, '公告和使用教程更新了，可点上方“贡献/使用教程”查看。']]
  );
});

test('getContentUpdateSnapshot falls back to cached snapshot when the live request fails', async () => {
  const cachedSnapshot = {
    status: 'update-available',
    promptVersion: 'announcement:2026-04-20T00:00:00Z',
    hasVisibleUpdates: true,
    latestUpdatedAt: '2026-04-20T00:00:00Z',
    latestUpdatedAtDisplay: '2026-04-20 08:00',
    items: [
      {
        slug: 'announcement',
        title: '站点公告',
        isEnabled: true,
        hasContent: true,
        isVisible: true,
        updatedAt: '2026-04-20T00:00:00Z',
        updatedAtDisplay: '2026-04-20 08:00',
      },
    ],
    portalUrl: 'https://apikey.qzz.io',
    apiUrl: 'https://apikey.qzz.io/api/content-summary',
    checkedAt: Date.now() - 1000,
  };

  const { api, getFetchCalls } = createContributionContentService({
    cachedSnapshot,
    fetchImpl: async () => {
      throw new Error('offline');
    },
  });

  const snapshot = await api.getContentUpdateSnapshot();

  assert.equal(getFetchCalls(), 1);
  assert.equal(snapshot.fromCache, true);
  assert.equal(snapshot.promptVersion, cachedSnapshot.promptVersion);
  assert.equal(snapshot.errorMessage, 'offline');
  assert.equal(snapshot.items[0].slug, 'announcement');
});
