// Session 60 (night2/B) — the VYNDR Lens + form heat. THE RULE: no raw
// streak renders alone; every row carries built-vs, tonight's matchup,
// difficulty, and a one-line read — all real or absent, never invented.

const { buildLens, applyLens, tonightFor, opposingPitcherFor, __internals } = require('../../src/services/streakLens');
const { computeFormHeat } = require('../../src/services/streaksService');

const SCHEDULE = [
  {
    homeTeam: { name: 'Detroit Tigers', abbreviation: 'DET' },
    awayTeam: { name: 'Tampa Bay Rays', abbreviation: 'TB' },
    gameTime: '2026-07-11T23:10:00Z',
  },
];
const PITCHERS = [
  {
    home: { team: 'Detroit Tigers', pitcher: 'Tarik Skubal', era: 2.41 },
    away: { team: 'Tampa Bay Rays', pitcher: 'Ryan Pepiot', era: 3.9 },
  },
];

describe('streakLens — tonight resolution', () => {
  test('finds the opponent + home/away for a team by mascot token', () => {
    const t = tonightFor('Tampa Bay Rays', SCHEDULE);
    expect(t.opponent).toBe('Detroit Tigers');
    expect(t.isHome).toBe(false);
  });

  test('resolves the OPPOSING probable SP (not the player-team SP)', () => {
    const sp = opposingPitcherFor('Tampa Bay Rays', PITCHERS);
    expect(sp.pitcher).toBe('Tarik Skubal');
    expect(sp.era).toBe(2.41);
  });
});

describe('streakLens — the one-line read', () => {
  const ROW = {
    sport: 'mlb', player: 'Brandon Lowe', team: 'Tampa Bay Rays',
    type: 'hit_streak', category: 'hits', currentStreak: 7,
    description: '7-game hit streak', opponents: ['Oakland Athletics', 'Los Angeles Angels'],
  };

  test('composes streak + built-vs + tonight + difficulty', () => {
    const lens = buildLens(ROW, { scheduleGames: SCHEDULE, pitcherGames: PITCHERS });
    expect(lens.builtVs).toEqual(['Oakland Athletics', 'Los Angeles Angels']);
    expect(lens.matchup).toBe('@ Detroit Tigers · SP Tarik Skubal (2.41 ERA)');
    expect(lens.difficulty).toBe('step up'); // 2.41 ERA ≤ 3.4
    expect(lens.read).toContain('7-game hit streak');
    expect(lens.read).toContain('built vs Oakland Athletics');
    expect(lens.read).toContain('a step up');
  });

  test('says LESS when context is missing — never invents', () => {
    const lens = buildLens({ ...ROW, opponents: [] }, {});
    expect(lens.builtVs).toBeNull();
    expect(lens.matchup).toBeNull();
    expect(lens.difficulty).toBeNull();
    expect(lens.read).toBe('7-game hit streak');
  });

  test('pitcher streaks do not get an opposing-SP difficulty read', () => {
    const lens = buildLens(
      { ...ROW, type: 'k_streak', description: '3-game 7+ K streak' },
      { scheduleGames: SCHEDULE, pitcherGames: PITCHERS },
    );
    expect(lens.matchup).toBe('@ Detroit Tigers'); // no SP line for pitchers
    expect(lens.difficulty).toBeNull();
  });

  test('ERA difficulty bands', () => {
    expect(__internals.eraDifficulty(2.9)).toBe('step up');
    expect(__internals.eraDifficulty(4.0)).toBe('neutral');
    expect(__internals.eraDifficulty(5.2)).toBe('step down');
    expect(__internals.eraDifficulty(null)).toBeNull();
  });

  test('applyLens attaches a lens to every row', () => {
    const rows = applyLens([ROW, { ...ROW, player: 'X' }], { scheduleGames: SCHEDULE, pitcherGames: PITCHERS });
    expect(rows).toHaveLength(2);
    expect(rows.every((r) => r.lens && r.lens.read)).toBe(true);
  });
});

describe('computeFormHeat — hot hitters / sluggers (correct rate math)', () => {
  const day = (n) => new Date(Date.now() - n * 86_400_000).toISOString().slice(0, 10);
  // 7-day window: 12-for-24 (.500); season .270 → hot hitter.
  const hotGames = [
    { date: day(1), opponent: 'Boston Red Sox', hits: 3, atBats: 4, totalBases: 7 },
    { date: day(2), opponent: 'Boston Red Sox', hits: 2, atBats: 4, totalBases: 5 },
    { date: day(3), opponent: 'New York Yankees', hits: 2, atBats: 4, totalBases: 2 },
    { date: day(4), opponent: 'New York Yankees', hits: 2, atBats: 4, totalBases: 6 },
    { date: day(5), opponent: 'New York Yankees', hits: 1, atBats: 4, totalBases: 1 },
    { date: day(6), opponent: 'Baltimore Orioles', hits: 2, atBats: 4, totalBases: 4 },
  ];

  test('flags a hot hitter vs his SEASON average with the honest line', () => {
    const rows = computeFormHeat(
      [{ name: 'Hot Guy', team: 'Tampa Bay Rays', games: hotGames, seasonRaw: { avg: '0.270', slg: '0.420' } }],
      'mlb',
    );
    const hitter = rows.find((r) => r.type === 'hot_hitter');
    expect(hitter).toBeTruthy();
    expect(hitter.rate).toBe(0.5); // 12/24, Σ/Σ not mean-of-rates
    expect(hitter.description).toContain('.500 over the last 7 days');
    expect(hitter.description).toContain('season .270');
    const slugger = rows.find((r) => r.type === 'hot_slugger');
    expect(slugger).toBeTruthy(); // 25 TB / 24 AB ≈ 1.042 SLG vs .420
    expect(slugger.opponents).toContain('Boston Red Sox');
  });

  test('small samples are refused (minAtt), not extrapolated', () => {
    const rows = computeFormHeat(
      [{ name: 'Two AB Guy', games: [{ date: day(1), hits: 2, atBats: 2 }], seasonRaw: { avg: '0.250' } }],
      'mlb',
    );
    expect(rows).toEqual([]);
  });

  test('no season baseline + no prior games → no claim', () => {
    const rows = computeFormHeat(
      [{ name: 'No Baseline', games: hotGames, seasonRaw: null }],
      'mlb',
    );
    expect(rows).toEqual([]); // all games in-window, nothing to trend against
  });
});
