import '@testing-library/jest-dom/vitest';
import { beforeEach, afterEach, vi } from 'vitest';
import { render } from '@testing-library/svelte';
import ToastHost from './src/lib/components/ToastHost.svelte';
import { clearToast } from './src/lib/stores/toast.svelte';

// Default svelte-query mock for the whole test suite. Most component
// tests just need useQueryClient to return SOMETHING — they never assert
// on the result. Tests that need to assert on invalidateQueries (named
// mock pattern) override this with their own per-file vi.mock. The
// override wins because per-file mocks take precedence over setup-file
// mocks in vitest.
vi.mock('@tanstack/svelte-query', async (orig) => {
  const actual = (await orig()) as Record<string, unknown>;
  return { ...actual, useQueryClient: () => ({ invalidateQueries: vi.fn() }) };
});

// Node 25 ships a partial localStorage global that lacks getItem/setItem/clear
// unless launched with --localstorage-file. jsdom sees Node's global and skips
// installing its own. Replace with an in-memory Storage-compatible polyfill so
// tests (and browser-only code under test) see a working localStorage.
class MemoryStorage implements Storage {
  private store = new Map<string, string>();
  get length() { return this.store.size; }
  clear(): void { this.store.clear(); }
  getItem(key: string): string | null { return this.store.get(key) ?? null; }
  key(i: number): string | null { return Array.from(this.store.keys())[i] ?? null; }
  removeItem(key: string): void { this.store.delete(key); }
  setItem(key: string, value: string): void { this.store.set(key, String(value)); }
}
const memLocal = new MemoryStorage();
const memSession = new MemoryStorage();
Object.defineProperty(globalThis, 'localStorage', { configurable: true, value: memLocal });
Object.defineProperty(globalThis, 'sessionStorage', { configurable: true, value: memSession });
if (typeof window !== 'undefined') {
  Object.defineProperty(window, 'localStorage', { configurable: true, value: memLocal });
  Object.defineProperty(window, 'sessionStorage', { configurable: true, value: memSession });
}

// jsdom doesn't implement Element.prototype.scrollIntoView. Components that
// call it (queue auto-scroll to the now-playing row, the alphabetical rail)
// would throw an unhandled TypeError in tests — which fails the run even when
// every assertion passes. No-op it; tests never assert on scroll position.
if (typeof Element !== 'undefined' && !Element.prototype.scrollIntoView) {
  Element.prototype.scrollIntoView = () => {};
}

// W-T3 moved toast rendering out of per-page markup into a single
// <ToastHost /> mounted in +layout.svelte. Tests render individual pages
// without the layout, so we mount ToastHost here so `pushToast()` calls
// from page code surface in the DOM the same way they do in production.
// `render()` from @testing-library/svelte registers auto-cleanup via the
// svelteTesting() vite plugin, so the host gets unmounted between tests
// alongside whatever component the test itself rendered. clearToast()
// resets the module-scope store state so a stale toast from one test
// can't leak into another.
beforeEach(() => {
  render(ToastHost);
});

afterEach(() => {
  clearToast();
});
