/**
 * Path-scoped rule files for .claude/rules/. Only generates a rule file
 * when the analysis shows that scope was actually exercised this session.
 *
 * Ported from AgentLens (`src/optimal-files/path-rules.js`). Pure.
 */

export function generatePathRules(analysis) {
  const a = analysis;
  const out = [];
  const generatedAt = a.generatedAt;
  const sid = (a.session && a.session.session_uuid) || '?';
  const provFooter = [
    '',
    '---',
    `Generated by DashClaw Code Sessions from session \`${sid}\` at \`${generatedAt}\`.`,
    `Edit freely. Path globs above scope the rule to the files it actually applies to.`,
  ].join('\n');

  if ((a.pathScopes.frontend || []).length >= 2) {
    const samplePaths = (a.pathScopes.frontend || []).slice(0, 4).map(s => s.target);
    const globs = inferGlobs(samplePaths, ['public/**/*.{html,css,js,ts,tsx,jsx}', 'src/components/**/*']);
    const md = [
      '---',
      'paths:',
      ...globs.map(g => `  - "${g}"`),
      '---',
      '',
      '# Frontend rules',
      '',
      '- Escape user-derived content before assigning to `innerHTML`. Use the project\'s `escapeHtml` helper.',
      '- Keep DOM updates batched — render full markup with `setHTML` rather than mutating in a loop.',
      '- Avoid introducing a build step unless the project already has one. Vanilla static assets stay vanilla.',
      '- Verify visible changes manually in the browser before declaring frontend work done.',
      provFooter,
    ].join('\n');
    out.push({
      path: '.claude/rules/frontend.md',
      kind: 'path-rules',
      title: 'Path-scoped rules — frontend',
      content: md + '\n',
      reason: `Session touched ${a.pathScopes.frontend.length} frontend files; rules scoped to ${globs.length} glob pattern${globs.length === 1 ? '' : 's'}.`,
      confidence: a.pathScopes.frontend.length >= 4 ? 'high' : 'medium',
      commitRecommendation: 'commit',
      group: 'optional',
    });
  }

  if ((a.pathScopes.backend || []).length >= 2) {
    const sample = (a.pathScopes.backend || []).slice(0, 4).map(s => s.target);
    const globs = inferGlobs(sample, ['src/routes/**/*.js', 'src/server.js']);
    const md = [
      '---',
      'paths:',
      ...globs.map(g => `  - "${g}"`),
      '---',
      '',
      '# API / backend rules',
      '',
      '- Validate inputs (`Number.isInteger`, schema) before touching the database.',
      '- Return structured JSON errors (`{ error: \'<reason>\' }`) — never leak stack traces to clients.',
      '- Auth-gate every route that mutates state with the existing `requireAuth(db)` middleware.',
      '- Run the test suite after route changes; `npm test` covers route shape regressions.',
      provFooter,
    ].join('\n');
    out.push({
      path: '.claude/rules/api.md',
      kind: 'path-rules',
      title: 'Path-scoped rules — API/backend',
      content: md + '\n',
      reason: `Session touched ${a.pathScopes.backend.length} backend file(s) under routes/server paths.`,
      confidence: a.pathScopes.backend.length >= 4 ? 'high' : 'medium',
      commitRecommendation: 'commit',
      group: 'optional',
    });
  }

  if ((a.pathScopes.tests || []).length >= 2 || a.verificationCommands.length >= 1) {
    const sample = (a.pathScopes.tests || []).slice(0, 4).map(s => s.target);
    const globs = inferGlobs(sample, ['tests/**/*.test.*', '**/*.spec.*']);
    const cmd = a.verificationCommands[0] && a.verificationCommands[0].command;
    const md = [
      '---',
      'paths:',
      ...globs.map(g => `  - "${g}"`),
      '---',
      '',
      '# Testing rules',
      '',
      cmd ? `- Run \`${cmd}\` after any change in this scope. It is the verification step the previous session used.`
          : `- Add a verification command for this scope and use it after every change.`,
      '- Write the failing assertion before the fix; expect-then-implement.',
      '- Prefer many small tests over one big one — one assertion per test where possible.',
      '- Cover the happy path AND the obvious failure modes (invalid input, missing auth, conflict).',
      provFooter,
    ].join('\n');
    out.push({
      path: '.claude/rules/testing.md',
      kind: 'path-rules',
      title: 'Path-scoped rules — testing',
      content: md + '\n',
      reason: cmd
        ? `Session ran \`${cmd}\` as its verification step.`
        : `Session touched ${a.pathScopes.tests.length} test file(s).`,
      confidence: a.verificationCommands.length ? 'high' : 'medium',
      commitRecommendation: 'commit',
      group: 'optional',
    });
  }

  if ((a.pathScopes.data || []).length >= 2) {
    const sample = (a.pathScopes.data || []).slice(0, 4).map(s => s.target);
    const globs = inferGlobs(sample, ['src/db.js', 'src/db/**/*', 'migrations/**/*.sql']);
    const md = [
      '---',
      'paths:',
      ...globs.map(g => `  - "${g}"`),
      '---',
      '',
      '# Data layer rules',
      '',
      '- Schema changes are additive: `ALTER TABLE ... ADD COLUMN` is safe; `DROP COLUMN` requires a migration plan.',
      '- Wrap multi-statement writes in `db.transaction(() => ...)` — partial writes are worse than rollbacks.',
      '- Index foreign keys you join on; check `EXPLAIN QUERY PLAN` for surprises.',
      '- Never log full row payloads — they may contain user data or tokens.',
      provFooter,
    ].join('\n');
    out.push({
      path: '.claude/rules/data-layer.md',
      kind: 'path-rules',
      title: 'Path-scoped rules — data layer',
      content: md + '\n',
      reason: `Session touched ${a.pathScopes.data.length} data-layer file(s).`,
      confidence: a.pathScopes.data.length >= 4 ? 'high' : 'medium',
      commitRecommendation: 'commit',
      group: 'optional',
    });
  }

  return out;
}

export function inferGlobs(samples, fallbacks) {
  if (!samples || !samples.length) return fallbacks;
  const dirs = new Set();
  const exts = new Set();
  for (const s of samples) {
    const norm = String(s).replace(/\\/g, '/');
    const ext = norm.match(/\.([A-Za-z0-9]+)$/);
    if (ext) exts.add(ext[1].toLowerCase());
    const segs = norm.split('/').filter(Boolean);
    if (segs.length >= 2) dirs.add(segs.slice(0, -1).join('/'));
  }
  if (!dirs.size) return fallbacks;
  const globs = [];
  for (const d of dirs) {
    const extGlob = exts.size ? `{${[...exts].join(',')}}` : '*';
    globs.push(`${d}/**/*.${extGlob}`);
  }
  return globs.slice(0, 4);
}
