import { describe, expect, it } from 'vitest';

import { __mlbPropInternals } from '../grok';

describe('structured signal narrative enrichment', () => {
  it('replaces generic no-signal narratives when sharp and steam rows exist', () => {
    const result = __mlbPropInternals.enrichStructuredSignalNarratives(
      {
        sharp_money_indicator: 'No sharp market interest detected amid stable pricing.',
        line_movement_analysis: 'Markets holding steady with no notable movement, signaling consensus on the slim favorite.',
      },
      {
        sharpMoves: [
          {
            market: 'total',
            lineFrom: 8.5,
            lineTo: 8,
            lineChange: -0.5,
            bookmaker: 'Pinnacle',
            isSteamMove: true,
          },
        ],
        lineMovements: [
          {
            marketType: 'total',
            openLine: 8.5,
            currentLine: 8,
            lineMovement: -0.5,
            movementDirection: 'down',
            sharpAction: 'over',
            steamMove: true,
            reverseLineMove: true,
          },
        ],
      },
    );

    expect(result.sharp_money_indicator).toContain('Sharp move detected on total');
    expect(result.sharp_money_indicator).toContain('8.5 to 8');
    expect(result.sharp_money_indicator).toContain('steam confirmation');
    expect(result.line_movement_analysis).toContain('Steam move detected on total');
    expect(result.line_movement_analysis).toContain('8.5 to 8');
    expect(result.line_movement_analysis).toContain('Reverse-line movement');
  });

  it('leaves real narratives alone when they already contain signal detail', () => {
    const result = __mlbPropInternals.enrichStructuredSignalNarratives(
      {
        sharp_money_indicator: 'Sharp action is leaning over as respected money pressures the total downward.',
        line_movement_analysis: 'Steam hit the total early and forced a quick half-run move across multiple venues.',
      },
      {
        sharpMoves: [
          {
            market: 'total',
            lineFrom: 8.5,
            lineTo: 8,
            lineChange: -0.5,
            isSteamMove: true,
          },
        ],
        lineMovements: [
          {
            marketType: 'total',
            openLine: 8.5,
            currentLine: 8,
            lineMovement: -0.5,
            steamMove: true,
          },
        ],
      },
    );

    expect(result).toEqual({
      sharp_money_indicator: 'Sharp action is leaning over as respected money pressures the total downward.',
      line_movement_analysis: 'Steam hit the total early and forced a quick half-run move across multiple venues.',
    });
  });
});

describe('forecast projection consistency sync', () => {
  it('rebuilds team scores and summary after a clamped margin change', () => {
    const result = __mlbPropInternals.syncForecastProjectionState(
      {
        summary: 'Rain Man forecasts Lakers to outscore Celtics by ~9 points.\nProjected combined score: ~231 points.\nHere\'s how Rain Man got there: Pace and shot quality lean Lakers.',
        winner_pick: 'Lakers',
        projected_winner: 'Lakers',
        forecast_side: 'Lakers',
        projected_margin: 4,
        projected_total_points: 231,
        projected_team_score_home: 120,
        projected_team_score_away: 111,
      } as any,
      {
        homeTeam: 'Lakers',
        awayTeam: 'Celtics',
        homeShort: 'LAL',
        awayShort: 'BOS',
        league: 'nba',
        spread: { home: { line: -3.5 }, away: { line: 3.5 } },
      },
      { rebuildNarrative: true },
    );

    expect(result.winner_pick).toBe('Lakers');
    expect(result.projected_winner).toBe('Lakers');
    expect(result.projected_team_score_home).toBe(117.5);
    expect(result.projected_team_score_away).toBe(113.5);
    expect(result.summary).toContain('Rain Man forecasts Lakers to outscore Celtics by ~4 points.');
    expect(result.summary).toContain('Projected combined score: ~231 points.');
  });

  it('flips the projected winner when the adjusted margin crosses zero', () => {
    const result = __mlbPropInternals.syncForecastProjectionState(
      {
        summary: 'Rain Man forecasts Lakers to outscore Celtics by ~6 points.\nProjected combined score: ~221 points.\nHere\'s how Rain Man got there: Lakers control the glass.',
        winner_pick: 'Lakers',
        projected_winner: 'Lakers',
        forecast_side: 'Celtics',
        projected_margin: -1.5,
        projected_total_points: 221,
        projected_team_score_home: 113.5,
        projected_team_score_away: 107.5,
      } as any,
      {
        homeTeam: 'Lakers',
        awayTeam: 'Celtics',
        homeShort: 'LAL',
        awayShort: 'BOS',
        league: 'nba',
        spread: { home: { line: -2.5 }, away: { line: 2.5 } },
      },
      { rebuildNarrative: true },
    );

    expect(result.winner_pick).toBe('Celtics');
    expect(result.projected_winner).toBe('Celtics');
    expect(result.projected_team_score_home).toBe(109.8);
    expect(result.projected_team_score_away).toBe(111.3);
    expect(result.summary).toContain('Rain Man forecasts Celtics to outscore Lakers by ~1.5 points.');
    expect(result.summary).not.toContain('Outcome lean:');
  });

  it('replaces stale winner-focused body copy when value side differs from the projected winner', () => {
    const result = __mlbPropInternals.syncForecastProjectionState(
      {
        summary: 'Rain Man forecasts Atlanta Braves to outscore Kansas City Royals by ~0.8 runs.\nProjected combined score: ~8.4 runs.\nHere\'s how Rain Man got there: Atlanta\'s lineup edge should carry the day and makes the Braves the side.',
        winner_pick: 'Atlanta Braves',
        projected_winner: 'Atlanta Braves',
        forecast_side: 'Kansas City Royals',
        projected_margin: 0.8,
        projected_total_points: 8.4,
        spread_edge: 2.5,
      } as any,
      {
        homeTeam: 'Atlanta Braves',
        awayTeam: 'Kansas City Royals',
        homeShort: 'ATL',
        awayShort: 'KC',
        league: 'mlb',
        spread: { home: { line: -1.5 }, away: { line: 1.5 } },
      },
      { rebuildNarrative: true },
    );

    expect(result.summary).toContain('Rain Man forecasts Atlanta Braves to outscore Kansas City Royals by ~0.8 runs.');
    expect(result.summary).toContain('Outcome lean: Atlanta Braves. Best value: Kansas City Royals against the run line.');
    expect(result.summary).toContain('Kansas City Royals at KC +1.5 carries the cleaner cushion versus the modeled margin.');
    expect(result.summary).toContain('Treat this as a run line-value call, not an outright winner flip.');
    expect(result.summary).not.toContain('makes the Braves the side');
  });
});
