import { describe, it, expect, beforeEach } from 'vitest';
import { ritualState, ritualKeys, markBriefSeen, briefSeen, RITUAL_ITEMS, DEFAULT_KEYS } from './ritual.js';

// Minimal localStorage stand-in (jsdom may not provide one in this config).
beforeEach(() => {
  const store = new Map();
  globalThis.localStorage = {
    getItem: (k) => (store.has(k) ? store.get(k) : null),
    setItem: (k, v) => store.set(k, String(v)),
    removeItem: (k) => store.delete(k),
    clear: () => store.clear(),
  };
});

const D = '2026-06-14';
const done = (s, key) => s.items.find((i) => i.key === key)?.done;

describe('ritualState', () => {
  it('defaults to the curated DEFAULT_KEYS set, none done', () => {
    const s = ritualState(D);
    expect(s.items.map((i) => i.key)).toEqual(DEFAULT_KEYS);
    expect(s.count).toBe(0);
    expect(s.total).toBe(DEFAULT_KEYS.length);
  });

  it('counts the brief only once the end-cap is marked', () => {
    expect(briefSeen(D)).toBe(false);
    markBriefSeen(D);
    expect(done(ritualState(D), 'brief')).toBe(true);
    expect(ritualState(D).count).toBe(1);
  });

  it('counts a word at a terminal state, a word search when cleared', () => {
    localStorage.setItem(`goodnews:word:5:${D}`, JSON.stringify({ status: 'playing', guesses: ['aaaaa'] }));
    expect(done(ritualState(D), 'word')).toBe(false); // in-progress isn't "enjoyed"
    localStorage.setItem(`goodnews:word:6:${D}`, JSON.stringify({ status: 'lost' }));
    expect(done(ritualState(D), 'word')).toBe(true);
    localStorage.setItem(`goodnews:wordsearch:med:${D}`, JSON.stringify({ status: 'done', foundWords: ['x'] }));
    expect(done(ritualState(D), 'wordsearch')).toBe(true);
  });

  it('counts Bloom only when the daily reached the top tier (top flag)', () => {
    localStorage.setItem(`goodnews:bloom:${D}`, JSON.stringify({ found: ['area'], score: 4 }));
    expect(done(ritualState(D), 'bloom')).toBe(false);          // played but not top tier
    localStorage.setItem(`goodnews:bloom:${D}`, JSON.stringify({ found: ['area'], score: 99, top: true }));
    expect(done(ritualState(D), 'bloom')).toBe(true);
  });

  it('honors a curated set — only chosen items appear and count', () => {
    markBriefSeen(D);
    localStorage.setItem(`goodnews:bloom:${D}`, JSON.stringify({ top: true }));
    const s = ritualState(D, ['brief', 'bloom']);     // reader's chosen set
    expect(s.items.map((i) => i.key)).toEqual(['brief', 'bloom']);
    expect(s.total).toBe(2);
    expect(s.count).toBe(2);
  });

  it('is scoped per server date — yesterday does not leak into today', () => {
    markBriefSeen('2026-06-13');
    expect(ritualState(D).count).toBe(0);
  });

  it('empty/missing date → nothing done (offline-safe)', () => {
    expect(ritualState('').count).toBe(0);
  });
});

describe('ritualKeys', () => {
  it('null/undefined → the curated default (NOT all eligible items)', () => {
    expect(ritualKeys(null)).toEqual(DEFAULT_KEYS);
    expect(ritualKeys(undefined)).toEqual(DEFAULT_KEYS);
    // default is a subset of eligible — adding a future eligible game must not auto-join it
    expect(DEFAULT_KEYS.every((k) => RITUAL_ITEMS.some((i) => i.key === k))).toBe(true);
  });
  it('an array → those keys in canonical order, unknown ignored', () => {
    expect(ritualKeys(['bloom', 'brief', 'nope'])).toEqual(['brief', 'bloom']);
    expect(ritualKeys([])).toEqual([]);   // explicitly empty set
  });
});
