/**
 * DS1 (DESIGN-SPEC §4 + §17) — source invariants for the Speed + Trust bugs.
 *   - React #418 hydration: no client-only value rendered in the SSR path
 *     without a mounted guard.
 *   - Loading walls: every named loader is a skeleton, not a text wall.
 *   - Persistence: the scan write uses the authoritative session token.
 */

const fs = require('fs');
const path = require('path');

const WEB = path.join(__dirname, '..', '..', 'web', 'src');
const read = (rel) => fs.readFileSync(path.join(WEB, rel), 'utf8');

describe('DS1 — React #418 hydration safety (§4, audit #5)', () => {
  const landing = read('app/page.tsx');

  test('landing no longer reads localStorage inside a useState initializer', () => {
    // The exact antipattern that caused #418: the client-only stored-session
    // check ran during render, so server (false) and client (true) diverged.
    expect(landing).not.toMatch(/useState<boolean>\(\s*\(\)\s*=>\s*hasStoredSession\(\)\s*\)/);
    expect(landing).not.toMatch(/useState\(\s*\(\)\s*=>\s*hasStoredSession/);
  });

  test('the client-only value is deferred behind a mounted flag', () => {
    // Server + first client render both compute maybeSignedIn from mounted=false.
    expect(landing).toMatch(/const\s+\[mounted,\s*setMounted\]\s*=\s*useState\(false\)/);
    expect(landing).toMatch(/setMounted\(true\)/);
    expect(landing).toMatch(/maybeSignedIn\s*=\s*mounted\s*&&\s*hasStoredSession\(\)/);
  });

  test('hasStoredSession still guards against server-side window access', () => {
    expect(landing).toMatch(/typeof window === 'undefined'/);
  });
});

describe('DS1 — loading walls are skeletons, never text (§4, audit #5)', () => {
  const files = {
    'dashboard slate load': 'app/dashboard/page.tsx',
    '/desk assembling': 'app/desk/page.tsx',
    '/ledger loading': 'app/ledger/page.tsx',
    'scan loading': 'app/scan/page.tsx',
    'landing redirect': 'app/page.tsx',
  };
  const BANNED = [
    'Loading the slate',
    'Assembling the pack',
    'Loading the model',
    /<p[^>]*>\s*Loading…\s*<\/p>/, // the bare ledger text loader
  ];

  for (const [name, rel] of Object.entries(files)) {
    test(`${name} contains no text-wall loader`, () => {
      const src = read(rel);
      for (const b of BANNED) {
        if (typeof b === 'string') expect(src).not.toContain(b);
        else expect(src).not.toMatch(b);
      }
    });
  }

  test('each loader path renders the shared Skeleton', () => {
    for (const rel of ['app/dashboard/page.tsx', 'app/desk/page.tsx', 'app/ledger/page.tsx', 'app/scan/page.tsx', 'app/page.tsx']) {
      const src = read(rel);
      expect(src).toMatch(/Skeleton/);
      expect(src).toMatch(/from '@\/components\/vyndr'/);
    }
  });

  test('the Skeleton primitive is tokenized (no raw hex) and reduced-motion-safe', () => {
    const skel = read('components/vyndr/Skeleton.tsx');
    // Uses the CSS class, no inline colors.
    expect(skel).toMatch(/vyndr-skeleton/);
    expect(skel).not.toMatch(/#[0-9a-fA-F]{3,8}/);
    const css = fs.readFileSync(path.join(WEB, 'app', 'globals.css'), 'utf8');
    expect(css).toMatch(/\.vyndr-skeleton\s*\{/);
    expect(css).toMatch(/var\(--bg-surface\)/);
    // The global prefers-reduced-motion rule freezes every animation.
    expect(css).toMatch(/@media \(prefers-reduced-motion: reduce\)/);
  });
});

describe('DS1 — scan→ledger persistence uses the authoritative token (§17)', () => {
  const scan = read('app/scan/page.tsx');

  test('scan pulls the bearer token from the live Supabase session', () => {
    expect(scan).toMatch(/session,/); // destructured from useAuth
    expect(scan).toMatch(/session\?\.access_token/);
  });

  test('scan no longer relies solely on the OAuth-only legacy localStorage key', () => {
    // The stale key may remain only as a FALLBACK after the session token.
    const m = scan.match(/session\?\.access_token\s*\|\|[\s\S]{0,120}sb-token/);
    expect(m).toBeTruthy();
  });
});
