import { beforeEach, describe, expect, it, vi } from 'vitest';

const testState = vi.hoisted(() => ({
  entriesMock: vi.fn(async () => [] as Array<['nsfw' | 'sfw', string]>),
  setItemMock: vi.fn(async () => undefined),
}));

vi.mock('@bitsocial/bitsocial-react-hooks/dist/lib/localforage-lru/index.js', () => ({
  default: {
    createInstance: () => ({
      entries: testState.entriesMock,
      setItem: testState.setItemMock,
    }),
  },
}));

const waitFor = async (predicate: () => boolean) => {
  for (let i = 0; i < 20; i += 1) {
    await Promise.resolve();
    if (predicate()) {
      return;
    }
  }
};

describe('useThemeStore', () => {
  beforeEach(() => {
    vi.resetModules();
    testState.entriesMock.mockReset();
    testState.entriesMock.mockResolvedValue([]);
    testState.setItemMock.mockReset();
    testState.setItemMock.mockResolvedValue(undefined);
  });

  it('loads stored themes on initialization', async () => {
    testState.entriesMock.mockResolvedValue([
      ['nsfw', 'tomorrow'],
      ['sfw', 'photon'],
    ]);

    const store = (await import('../use-theme-store')).default;
    await waitFor(() => store.getState().themes.nsfw === 'tomorrow');

    expect(store.getState().themes).toEqual({
      nsfw: 'tomorrow',
      sfw: 'photon',
    });
    expect(store.getState().currentTheme).toBeNull();
  });

  it('setTheme persists the updated theme and updates currentTheme', async () => {
    const store = (await import('../use-theme-store')).default;
    await waitFor(() => testState.entriesMock.mock.calls.length > 0);

    await store.getState().setTheme('nsfw', 'photon');

    expect(testState.setItemMock).toHaveBeenCalledWith('nsfw', 'photon');
    expect(store.getState().themes.nsfw).toBe('photon');
    expect(store.getState().currentTheme).toBe('photon');
  });

  it('getTheme can skip updating currentTheme when requested', async () => {
    const store = (await import('../use-theme-store')).default;
    await waitFor(() => testState.entriesMock.mock.calls.length > 0);

    expect(store.getState().getTheme('sfw', false)).toBe('yotsuba-b');
    expect(store.getState().currentTheme).toBeNull();

    expect(store.getState().getTheme('sfw')).toBe('yotsuba-b');
    expect(store.getState().currentTheme).toBe('yotsuba-b');
  });
});
