// Wave 3 (Addition 2) — RECORD BY GRADE TIER.
// The tier calibration IS the credibility: A+ wins more than A, A more than
// B. This suite locks (a) the shared row-building logic, (b) the tier order,
// and (c) that the ONE shared TierRecord component is imported + rendered on
// all three record surfaces (dashboard, /u, ledger). Plain-JS Jest — the .tsx
// is asserted against source (same pattern as publicProfilePage/vyndrAppShell).

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

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

const { buildTierRows, TIER_ORDER, anyTierReady, isEdgeTier } = require('../../web/src/lib/tierRecord');

describe('buildTierRows — honesty rules', () => {
  // A ≥20 tier carries a real hit_pct (gate applied upstream); a small tier
  // arrives with hit_pct null even though it has settles.
  const byTier = {
    'A+': { settled: 22, hits: 18, misses: 4, pushes: 0, hit_pct: 82 },
    A: { settled: 25, hits: 17, misses: 8, pushes: 0, hit_pct: 68 },
    B: { settled: 3, hits: 2, misses: 1, pushes: 0, hit_pct: null }, // small sample
  };

  test('shows each tier W-L record ALWAYS, even at small n', () => {
    const rows = buildTierRows(byTier);
    const b = rows.find((r) => r.tier === 'B');
    expect(b).toBeTruthy();
    expect(b.record).toBe('2-1'); // honest at n=3
    const ap = rows.find((r) => r.tier === 'A+');
    expect(ap.record).toBe('18-4');
  });

  test('shows the hit-% ONLY when hit_pct != null; else RECORD BUILDING', () => {
    const rows = buildTierRows(byTier);
    const ap = rows.find((r) => r.tier === 'A+');
    expect(ap.ready).toBe(true);
    expect(ap.hitPct).toBe(82);

    // Small-sample tier: no percentage, building copy with the settled count.
    const b = rows.find((r) => r.tier === 'B');
    expect(b.ready).toBe(false);
    expect(b.hitPct).toBeNull();
    expect(b.buildingLabel).toBe('RECORD BUILDING · 3 settled');
  });

  test('never fabricates a 0% from a null hit_pct (Number(null)===0 guard)', () => {
    const rows = buildTierRows({ C: { settled: 5, hits: 0, misses: 0, pushes: 0, hit_pct: null } });
    expect(rows[0].hitPct).toBeNull();
    expect(rows[0].ready).toBe(false);
  });

  test('omits tiers with zero settled reads (no fake empty rows)', () => {
    const rows = buildTierRows({ A: { settled: 0, hits: 0, misses: 0, hit_pct: null }, B: { settled: 4, hits: 3, misses: 1, hit_pct: null } });
    expect(rows.map((r) => r.tier)).toEqual(['B']);
  });

  test('empty / missing map → no rows (self-hides)', () => {
    expect(buildTierRows(null)).toEqual([]);
    expect(buildTierRows(undefined)).toEqual([]);
    expect(buildTierRows({})).toEqual([]);
  });
});

describe('tier order + edge color contract', () => {
  test('renders A+ → F in canonical order', () => {
    expect(TIER_ORDER).toEqual(['A+', 'A', 'B', 'C', 'D', 'F']);
  });

  test('buildTierRows preserves A+ → F order regardless of map insertion order', () => {
    const rows = buildTierRows({
      F: { settled: 2, hits: 0, misses: 2, hit_pct: null },
      A: { settled: 3, hits: 2, misses: 1, hit_pct: null },
      'A+': { settled: 4, hits: 4, misses: 0, hit_pct: null },
      C: { settled: 5, hits: 2, misses: 3, hit_pct: null },
    });
    expect(rows.map((r) => r.tier)).toEqual(['A+', 'A', 'C', 'F']);
  });

  test('GLOW RESERVED FOR A-TIER — only A+/A are edge tiers', () => {
    expect(isEdgeTier('A+')).toBe(true);
    expect(isEdgeTier('A')).toBe(true);
    expect(isEdgeTier('B')).toBe(false);
    expect(isEdgeTier('C')).toBe(false);
    expect(isEdgeTier('F')).toBe(false);
  });

  test('anyTierReady reflects the upstream n≥20 gate', () => {
    expect(anyTierReady({ A: { settled: 5, hits: 3, misses: 2, hit_pct: null } })).toBe(false);
    expect(anyTierReady({ A: { settled: 25, hits: 17, misses: 8, hit_pct: 68 } })).toBe(true);
  });
});

describe('the ONE shared component reaches all three record surfaces', () => {
  test('TierRecord.tsx exists and is exported from the vyndr barrel', () => {
    expect(exists('components/vyndr/TierRecord.tsx')).toBe(true);
    expect(read('components/vyndr/index.ts')).toContain("export { default as TierRecord } from './TierRecord'");
  });

  test('TierRecord renders W-L always + % only when ready, else BUILDING', () => {
    const src = read('components/vyndr/TierRecord.tsx');
    expect(src).toContain('buildTierRows');
    expect(src).toContain('{r.record}');          // W-L always
    expect(src).toContain('{r.hitPct}% HIT');     // % only in the ready branch
    expect(src).toContain('RECORD BUILDING · {r.settled} settled');
  });

  test('/u PublicProfile imports AND renders TierRecord', () => {
    const src = read('app/u/[handle]/PublicProfile.tsx');
    expect(src).toMatch(/import TierRecord from '@\/components\/vyndr\/TierRecord'/);
    expect(src).toContain('<TierRecord');
    expect(src).toContain('by_tier'); // the aggregate carries the tier buckets
  });

  test('dashboard imports AND renders TierRecord', () => {
    const src = read('app/dashboard/page.tsx');
    expect(src).toMatch(/TierRecord/);
    expect(src).toContain('<TierRecord');
  });

  test('ledger uses the shared TierRecord (single source, no inline table)', () => {
    const src = read('app/ledger/page.tsx');
    expect(src).toContain('TierRecord');
    expect(src).toContain('<TierRecord');
    // the old inline per-tier component is gone (folded into the shared one)
    expect(src).not.toContain('function TierCalibration');
  });
});
