// P3f — cross-account dedup invariant pin.
//
// `expo-image` derives the cache key from the URL by default. Pixelfed CDN
// media URLs are content-hashed (`/storage/m/<hash>/avatar.jpg`), so two
// signed-in accounts on the same instance viewing the same post share the
// disk cache automatically — at zero engineering cost.
//
// Injecting `accountId` (or any per-account state) into the `<Image>` /
// `<ImageBackground>` `cacheKey` prop would break this invariant: the same
// URL would resolve to two cache slots, silently doubling the per-account
// disk footprint and undermining the whole "Halflight-on-five-accounts is
// not five times the disk weight" property the storage budget assumes.
//
// Static-analysis test: walk every `.ts` / `.tsx` under `src/` and assert
// that no source line that mentions `cacheKey` also mentions `account` or
// `acct(`. Cheap, load-bearing, and survives refactors that move components
// around — the contract is per-substring, not per-file.

import * as fs from 'node:fs'
import * as path from 'node:path'

const SRC_ROOT = path.resolve(__dirname, '..', 'src')

function walk(dir: string, out: string[]): void {
  for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
    if (entry.name === 'node_modules' || entry.name.startsWith('.')) continue
    const full = path.join(dir, entry.name)
    if (entry.isDirectory()) {
      walk(full, out)
    } else if (entry.isFile() && /\.(ts|tsx)$/.test(entry.name)) {
      out.push(full)
    }
  }
}

function relPath(p: string): string {
  return path.relative(path.resolve(__dirname, '..'), p)
}

describe('Image cacheKey contract — no per-account injection', () => {
  it('no source file injects account state into a cacheKey', () => {
    const files: string[] = []
    walk(SRC_ROOT, files)
    const violations: { file: string; line: number; text: string }[] = []
    for (const file of files) {
      const lines = fs.readFileSync(file, 'utf8').split('\n')
      for (let i = 0; i < lines.length; i++) {
        const line = lines[i]
        // Skip comments — the contract is about runtime usage, not docs.
        const stripped = line.replace(/\/\/.*$/, '').replace(/\/\*[\s\S]*?\*\//g, '')
        if (!/cacheKey/.test(stripped)) continue
        if (/\baccount\b|\bacct\(|\baccountId\b/i.test(stripped)) {
          violations.push({ file: relPath(file), line: i + 1, text: line.trim() })
        }
      }
    }
    if (violations.length > 0) {
      const lines = violations
        .map((v) => `  ${v.file}:${v.line} → ${v.text}`)
        .join('\n')
      throw new Error(
        `cacheKey contract violation — these sites bind cache keys to per-account state:\n${lines}\n\n` +
          'Image / ImageBackground cacheKey must stay URL-derived. Injecting accountId silently doubles disk footprint per account and breaks cross-account dedup.'
      )
    }
    expect(violations).toEqual([])
  })

  it('the contract test sees the source tree', () => {
    // Sanity check — if the walker stops finding files (path drift,
    // typescript file extensions changed), the previous test would pass
    // vacuously. Pin a non-zero file count here so the contract has teeth.
    const files: string[] = []
    walk(SRC_ROOT, files)
    expect(files.length).toBeGreaterThan(50)
  })
})
