# Bracket Expansion Plan

## Problem Statement

Current bracket system only supports 4 and 8 team single-elimination brackets. We need to support:
- **Standard brackets**: 4, 8, 16, 32 teams
- **March Madness**: 68 teams with unique structure
  - First Four: 4 play-in games (8 teams)
  - Round of 64: 32 games (64 teams including First Four winners)
  - Round of 32, Sweet Sixteen, Elite Eight, Final Four, Championship
  - **Only Elite Eight and beyond score fantasy points** (per Q18)
  - Play-in teams can be any seeds (e.g., 11a vs 11b, 16a vs 16b), not just bottom seeds

## Current Implementation

**What we have:**
- `generateSingleEliminationBracket(eventId, participantIds[])`
- Supports 4 or 8 teams only
- Creates matches for all rounds automatically
- Simple sequential seeding (1 vs 2, 3 vs 4, etc.)

**Limitations:**
- Fixed bracket sizes (4, 8)
- No play-in game support
- No concept of "scoring rounds" vs "non-scoring rounds"
- No flexible seeding/matchup configuration

## Proposed Solution: Hybrid Approach

### Option 1: Template-Based Bracket System ✅ **RECOMMENDED**

Create pre-defined bracket templates for common structures, with manual override capability.

#### Bracket Templates

```typescript
interface BracketTemplate {
  id: string;
  name: string;
  totalTeams: number;
  rounds: BracketRound[];
  scoringStartsAtRound?: string; // e.g., "Elite Eight" for March Madness
}

interface BracketRound {
  name: string; // "First Four", "Round of 64", "Elite Eight", etc.
  matchCount: number;
  feedsInto?: string; // Which round winners advance to
  isScoring: boolean; // Does this round affect fantasy points?
}

// Example templates:
const BRACKET_TEMPLATES = {
  NCAA_68: {
    id: 'ncaa_68',
    name: 'NCAA March Madness (68 teams)',
    totalTeams: 68,
    scoringStartsAtRound: 'Elite Eight',
    rounds: [
      { name: 'First Four', matchCount: 4, feedsInto: 'Round of 64', isScoring: false },
      { name: 'Round of 64', matchCount: 32, feedsInto: 'Round of 32', isScoring: false },
      { name: 'Round of 32', matchCount: 16, feedsInto: 'Sweet Sixteen', isScoring: false },
      { name: 'Sweet Sixteen', matchCount: 8, feedsInto: 'Elite Eight', isScoring: false },
      { name: 'Elite Eight', matchCount: 4, feedsInto: 'Final Four', isScoring: true }, // 8 teams, share 5-8th
      { name: 'Final Four', matchCount: 2, feedsInto: 'Championship', isScoring: true }, // Losers share 3-4th
      { name: 'Championship', matchCount: 1, feedsInto: null, isScoring: true }, // Winner 1st, Loser 2nd
    ],
  },

  NFL_14: {
    id: 'nfl_14',
    name: 'NFL Playoffs (14 teams)',
    totalTeams: 14,
    scoringStartsAtRound: 'Wild Card',
    rounds: [
      { name: 'Wild Card', matchCount: 6, feedsInto: 'Divisional', isScoring: false }, // 2 teams get bye
      { name: 'Divisional', matchCount: 4, feedsInto: 'Conference Championship', isScoring: true }, // QF, share 5-8th
      { name: 'Conference Championship', matchCount: 2, feedsInto: 'Super Bowl', isScoring: true }, // SF, share 3-4th
      { name: 'Super Bowl', matchCount: 1, feedsInto: null, isScoring: true }, // Finals, 1st/2nd
    ],
  },

  NBA_16: {
    id: 'nba_16',
    name: 'NBA Playoffs (16 teams)',
    totalTeams: 16,
    scoringStartsAtRound: 'Conference Quarterfinals',
    rounds: [
      { name: 'First Round', matchCount: 8, feedsInto: 'Conference Semifinals', isScoring: false },
      { name: 'Conference Semifinals', matchCount: 4, feedsInto: 'Conference Finals', isScoring: true }, // QF, share 5-8th
      { name: 'Conference Finals', matchCount: 2, feedsInto: 'NBA Finals', isScoring: true }, // SF, share 3-4th
      { name: 'NBA Finals', matchCount: 1, feedsInto: null, isScoring: true }, // Finals, 1st/2nd
    ],
  },

  SIMPLE_16: {
    id: 'simple_16',
    name: 'Simple 16-Team Bracket',
    totalTeams: 16,
    scoringStartsAtRound: 'Quarterfinals',
    rounds: [
      { name: 'Round of 16', matchCount: 8, feedsInto: 'Quarterfinals', isScoring: false },
      { name: 'Quarterfinals', matchCount: 4, feedsInto: 'Semifinals', isScoring: true }, // Share 5-8th
      { name: 'Semifinals', matchCount: 2, feedsInto: 'Finals', isScoring: true }, // Share 3-4th
      { name: 'Finals', matchCount: 1, feedsInto: null, isScoring: true }, // 1st/2nd
    ],
  },

  SIMPLE_32: {
    id: 'simple_32',
    name: 'Simple 32-Team Bracket',
    totalTeams: 32,
    scoringStartsAtRound: 'Quarterfinals',
    rounds: [
      { name: 'Round of 32', matchCount: 16, feedsInto: 'Round of 16', isScoring: false },
      { name: 'Round of 16', matchCount: 8, feedsInto: 'Quarterfinals', isScoring: false },
      { name: 'Quarterfinals', matchCount: 4, feedsInto: 'Semifinals', isScoring: true },
      { name: 'Semifinals', matchCount: 2, feedsInto: 'Finals', isScoring: true },
      { name: 'Finals', matchCount: 1, feedsInto: null, isScoring: true },
    ],
  },
};
```

#### UI Flow

**Step 1: Select Template**
```
When creating a bracket event:
1. Admin selects bracket template from dropdown
2. Shows preview of rounds and scoring structure
3. Option to customize (add/remove rounds, change scoring start point)
```

**Step 2: Assign Participants**
```
For March Madness (68 teams):
- Show all 68 slots grouped by round
- First Four: 8 slots (4 matchups) - manual seeding (e.g., "11a vs 11b", "16a vs 16b")
- Round of 64: 60 slots (remaining teams) + 4 TBD (from First Four winners)
- Admin can assign any participant to any slot

For simpler brackets (4, 8, 16):
- Linear list of slots
- Drag-and-drop or dropdown selection
- Traditional seeding (1 vs 16, 2 vs 15, etc.)
```

**Step 3: Generate Bracket**
```
System creates:
- All playoff_matches records for all rounds
- Properly linked feedsInto relationships
- Marks which rounds contribute to scoring
- Sets initial participant assignments
```

#### Database Schema Additions

```typescript
// Add to playoff_matches table
playoff_matches {
  // ... existing fields

  // NEW FIELDS:
  isScoring: boolean (default: true) // Does this match affect fantasy points?
  templateRound: varchar(50) // "First Four", "Round of 64", etc.
  seedInfo: varchar(50) // "1 vs 16", "11a vs 11b", etc. (for display)
}

// Add to scoring_events table
scoring_events {
  // ... existing fields

  // NEW FIELDS:
  bracketTemplateId: varchar(50) // "ncaa_68", "nfl_14", etc.
  scoringStartsAtRound: varchar(50) // Which round starts fantasy scoring
}
```

#### Scoring Logic Updates

```typescript
/**
 * Process playoff event completion - updated for template system
 */
async function processPlayoffEvent(eventId: string) {
  const event = await getScoringEventById(eventId);
  const matches = await findPlayoffMatchesByEventId(eventId);

  // Filter to only scoring matches
  const scoringMatches = matches.filter(m => m.isScoring);

  // Determine which placements to assign based on templateRound
  // Elite Eight losers (4 teams) -> share 5-8th
  // Final Four losers (2 teams) -> share 3-4th
  // Championship loser (1 team) -> 2nd
  // Championship winner (1 team) -> 1st

  // For non-scoring rounds: assign 0 points (per Q20)
  const nonScoringLosers = matches
    .filter(m => !m.isScoring && m.loserId)
    .map(m => m.loserId);

  for (const loserId of nonScoringLosers) {
    await setParticipantResult(loserId, event.sportsSeasonId, null, 0);
  }
}
```

#### Admin UI Changes

**Bracket Generation Page:**
```tsx
<Card>
  <CardHeader>
    <CardTitle>Select Bracket Template</CardTitle>
  </CardHeader>
  <CardContent>
    <Select name="templateId">
      <SelectItem value="simple_4">Simple 4-Team</SelectItem>
      <SelectItem value="simple_8">Simple 8-Team</SelectItem>
      <SelectItem value="simple_16">Simple 16-Team</SelectItem>
      <SelectItem value="nba_16">NBA Playoffs (16 teams)</SelectItem>
      <SelectItem value="nfl_14">NFL Playoffs (14 teams)</SelectItem>
      <SelectItem value="simple_32">Simple 32-Team</SelectItem>
      <SelectItem value="ncaa_68">March Madness (68 teams)</SelectItem>
    </Select>

    {/* Show template details when selected */}
    <div className="mt-4">
      <h4>Rounds:</h4>
      {selectedTemplate.rounds.map(round => (
        <div key={round.name}>
          {round.name} - {round.matchCount} matches
          {round.isScoring && <Badge>Scoring Round</Badge>}
        </div>
      ))}
    </div>
  </CardContent>
</Card>

<Card>
  <CardHeader>
    <CardTitle>Assign Participants ({templateTeamCount} slots)</CardTitle>
  </CardHeader>
  <CardContent>
    {/* For March Madness: group by round */}
    {template.id === 'ncaa_68' ? (
      <>
        <h4>First Four (Play-in Games)</h4>
        {/* 4 matchups, 8 slots with seed labels */}
        <MatchupSelector
          matchup={1}
          label1="11a vs"
          label2="11b"
          participants={participants}
        />

        <h4>Round of 64</h4>
        {/* 28 direct assignments + 4 TBD from First Four */}
        <SlotSelector
          slots={60}
          tbdSlots={4}
          participants={participants}
        />
      </>
    ) : (
      /* Simple linear assignment for other brackets */
      <LinearSlotSelector
        slots={templateTeamCount}
        participants={participants}
      />
    )}
  </CardContent>
</Card>
```

### Implementation Phases

**Phase 2.6: Template System Foundation**
- [ ] Define bracket template type and constants
- [ ] Add `isScoring` and `templateRound` to playoff_matches schema
- [ ] Add `bracketTemplateId` and `scoringStartsAtRound` to scoring_events
- [ ] Create database migration
- [ ] Update playoff-match model to support templates

**Phase 2.7: Simple Template Expansion (4, 8, 16, 32)**
- [ ] Create template definitions for 4, 8, 16, 32 team brackets
- [ ] Update `generateBracketFromTemplate()` function
- [ ] Update bracket generation UI to use template selector
- [ ] Test with 16-team and 32-team brackets
- [ ] Update scoring calculator for non-scoring rounds (0 points)

**Phase 2.8: March Madness Template (68 teams)**
- [ ] Create NCAA_68 template definition
- [ ] Build First Four matchup assignment UI
- [ ] Build Round of 64 with TBD slot handling
- [ ] Implement winner advancement from First Four to Round of 64
- [ ] Test complete 68-team bracket flow
- [ ] Verify Elite Eight scoring starts correctly

**Phase 2.9: NFL/NBA Templates**
- [ ] Create NFL_14 template (with bye weeks)
- [ ] Create NBA_16 template
- [ ] Handle bye week logic (teams skip first round)
- [ ] Test both templates

## Alternative Considered: Manual Match Creation

**Pros:**
- Maximum flexibility
- Works for any structure

**Cons:**
- Too complex for admins
- Error-prone (easy to miss connections)
- No validation of bracket structure
- Time-consuming for large brackets

**Verdict:** Not recommended. Templates provide better UX with flexibility where needed.

## Open Questions

1. **Custom Templates**: Should admins be able to save custom bracket templates for reuse?
   - **Recommendation**: Not in initial implementation. Add if requested.

2. **Seed Validation**: Should system validate proper bracket structure (e.g., 1 seed plays 16 seed)?
   - **Recommendation**: No. Allow flexible seeding for play-ins and special cases.

3. **Series Support**: Should we support best-of-7 series (NBA/NHL)?
   - **Recommendation**: Not initially. Just track series winner for now.

4. **Bracket Visualization**: Show traditional bracket tree diagram?
   - **Recommendation**: Phase 3 enhancement. Current table view sufficient for Phase 2.

## Success Criteria

✅ Admin can create 4, 8, 16, 32 team brackets
✅ Admin can create March Madness 68-team bracket with First Four
✅ Admin can assign any participant to any slot (flexible seeding)
✅ System correctly identifies which rounds score fantasy points
✅ Participants eliminated in non-scoring rounds get 0 points
✅ Elite Eight and beyond calculate placements correctly
✅ Winner advancement works across all bracket sizes
