import fs from 'fs';
import path from 'path';

/**
 * Guards against "stranded" CSS: when markup moves between components, its
 * rules must move with it. CSS Modules hash class names per file, so a rule
 * left behind in another stylesheet silently stops applying — exactly how the
 * header's mobile `.headerDetails { display: none }` (and the section-nav
 * mobile swap) stopped working when the detail view was split into a client
 * shell plus server sections.
 */

const SCHOOL_DIR = path.join(__dirname, '..', '..', 'components', 'school');

function classesDefinedIn(css: string): Set<string> {
  return new Set(Array.from(css.matchAll(/\.(-?[_a-zA-Z][\w-]*)/g), (m) => m[1]));
}

function classesUsedIn(tsx: string): Set<string> {
  return new Set(Array.from(tsx.matchAll(/\bstyles\.([_a-zA-Z][\w]*)/g), (m) => m[1]));
}

const components = fs
  .readdirSync(SCHOOL_DIR)
  .filter((f) => f.endsWith('.tsx'))
  .map((file) => {
    const source = fs.readFileSync(path.join(SCHOOL_DIR, file), 'utf8');
    const importMatch = source.match(/import\s+styles\s+from\s+['"](.+?\.module\.css)['"]/);
    return { file, source, stylesheet: importMatch?.[1] };
  })
  .filter((c) => c.stylesheet);

describe('school detail stylesheets', () => {
  it.each(components.map((c) => [c.file, c.source, c.stylesheet as string]))(
    '%s only uses classes its own stylesheet defines',
    (_file, source, stylesheet) => {
      const css = fs.readFileSync(path.join(SCHOOL_DIR, stylesheet), 'utf8');
      const defined = classesDefinedIn(css);
      const missing = Array.from(classesUsedIn(source)).filter((c) => !defined.has(c));
      expect(missing).toEqual([]);
    },
  );
});
