diff --git a/backend/app/core/state_manager.py b/backend/app/core/state_manager.py index aabb034..3350cbd 100644 --- a/backend/app/core/state_manager.py +++ b/backend/app/core/state_manager.py @@ -435,65 +435,81 @@ class StateManager: else: state.outs = outs_after - # Recover batter indices - find which batter is next based on last play - last_batter_order = last_play.get("batting_order") - logger.info(f"Recovery: last_batter_order from play #{last_play['play_number']} = {last_batter_order}") + # Recover batter indices - find last play for EACH team separately + # This is critical after inning changes - we need both teams' positions + away_plays = [p for p in completed_plays if p.get("half") == "top"] + home_plays = [p for p in completed_plays if p.get("half") == "bottom"] - if last_batter_order: - # Next batter is last_batter + 1, wrapping at 9 - next_batter_order = (last_batter_order % 9) + 1 - - # Set the correct index for the batting team - # Index is order - 1 (0-indexed) - next_batter_idx = next_batter_order - 1 - - if batting_team_id == away_team_id: - state.away_team_batter_idx = next_batter_idx - state.home_team_batter_idx = 0 + # Away team's last at-bat + if away_plays: + last_away_play = max(away_plays, key=lambda p: p["play_number"]) + away_last_order = last_away_play.get("batting_order") + if away_last_order: + # Next batter is last_batter + 1, wrapping at 9 + state.away_team_batter_idx = away_last_order % 9 # Already 0-indexed after mod + logger.info(f"Recovery: Away team last batter was #{away_last_order}, next is #{state.away_team_batter_idx + 1}") else: - state.home_team_batter_idx = next_batter_idx state.away_team_batter_idx = 0 - - logger.info(f"Recovery: Set batter indices - next_order={next_batter_order}, next_idx={next_batter_idx}, batting_team={batting_team_id}") - - # Update current_batter to match the recovered batter index - # Get batting lineup sorted by batting_order - batting_lineup = [ - get_lineup_player(lineup["id"]) - for lineup in lineups - if lineup.get("team_id") == batting_team_id - and lineup.get("batting_order") is not None - and lineup.get("is_active") - ] - logger.info(f"Recovery: Found {len(batting_lineup)} batters (before None filter)") - - # Filter out None values (if any) - batting_lineup = [b for b in batting_lineup if b is not None] - logger.info(f"Recovery: {len(batting_lineup)} batters after None filter") - - batting_lineup_sorted = sorted( - batting_lineup, key=lambda x: x.batting_order or 0 - ) - logger.info(f"Recovery: Sorted lineup has {len(batting_lineup_sorted)} batters") - - # Set current_batter to the batter at next_batter_idx - if next_batter_idx < len(batting_lineup_sorted): - state.current_batter = batting_lineup_sorted[next_batter_idx] - logger.info( - f"Recovery: ✓ Set current_batter to order={next_batter_order}, idx={next_batter_idx}, " - f"card_id={state.current_batter.card_id}, batting_order={state.current_batter.batting_order}" - ) - else: - logger.warning( - f"Recovery: ✗ Batter index {next_batter_idx} out of range for batting order " - f"(lineup size: {len(batting_lineup_sorted)})" - ) - logger.info(f"Recovery: Calculated next_order={next_batter_order}, next_idx={next_batter_idx}") else: - logger.info("Recovery: No last_batter_order found - using defaults") - # Fallback if no batting order in last play + # Away team hasn't batted yet (game just started or first pitch) state.away_team_batter_idx = 0 + logger.info("Recovery: Away team has no plays yet, starting at batter #1") + + # Home team's last at-bat + if home_plays: + last_home_play = max(home_plays, key=lambda p: p["play_number"]) + home_last_order = last_home_play.get("batting_order") + if home_last_order: + # Next batter is last_batter + 1, wrapping at 9 + state.home_team_batter_idx = home_last_order % 9 # Already 0-indexed after mod + logger.info(f"Recovery: Home team last batter was #{home_last_order}, next is #{state.home_team_batter_idx + 1}") + else: + state.home_team_batter_idx = 0 + else: + # Home team hasn't batted yet state.home_team_batter_idx = 0 + logger.info("Recovery: Home team has no plays yet, starting at batter #1") + + # Determine which index to use for current_batter + if batting_team_id == away_team_id: + next_batter_idx = state.away_team_batter_idx + else: + next_batter_idx = state.home_team_batter_idx + + logger.info(f"Recovery: Set batter indices - away={state.away_team_batter_idx}, home={state.home_team_batter_idx}, current batting team uses idx={next_batter_idx}") + + # Update current_batter to match the recovered batter index + # Get batting lineup sorted by batting_order + batting_lineup = [ + get_lineup_player(lineup["id"]) + for lineup in lineups + if lineup.get("team_id") == batting_team_id + and lineup.get("batting_order") is not None + and lineup.get("is_active") + ] + logger.info(f"Recovery: Found {len(batting_lineup)} batters (before None filter)") + + # Filter out None values (if any) + batting_lineup = [b for b in batting_lineup if b is not None] + logger.info(f"Recovery: {len(batting_lineup)} batters after None filter") + + batting_lineup_sorted = sorted( + batting_lineup, key=lambda x: x.batting_order or 0 + ) + logger.info(f"Recovery: Sorted lineup has {len(batting_lineup_sorted)} batters") + + # Set current_batter to the batter at next_batter_idx + if next_batter_idx < len(batting_lineup_sorted): + state.current_batter = batting_lineup_sorted[next_batter_idx] + logger.info( + f"Recovery: ✓ Set current_batter to idx={next_batter_idx}, " + f"card_id={state.current_batter.card_id}, batting_order={state.current_batter.batting_order}" + ) + else: + logger.warning( + f"Recovery: ✗ Batter index {next_batter_idx} out of range for batting order " + f"(lineup size: {len(batting_lineup_sorted)})" + ) # Always start at awaiting_defensive on recovery # (Users can re-submit decisions if they refreshed mid-workflow)