# Business Logic

## 10.1 Services Layer

### Service Architecture
The business logic is organized into service classes that handle complex operations and maintain separation of concerns.

```
app/Services/
├── TournamentBracketService.php    # Bracket generation and management
├── MpesaService.php               # Payment processing
├── OtpService.php                 # OTP generation and verification
├── TeamRegistrationService.php    # Team registration workflow
├── DataScopingService.php         # Data access control
├── EmailSettingsService.php       # Email configuration
└── TournamentAlgorithmTester.php  # Algorithm testing
```

### Service Design Principles
- **Single Responsibility**: Each service handles one business domain
- **Dependency Injection**: Services are injected where needed
- **Error Handling**: Comprehensive error handling and logging
- **Transaction Management**: Database transaction management
- **Validation**: Input validation and business rule enforcement

## 10.2 Tournament Algorithms

### TournamentBracketService
```php
class TournamentBracketService
{
    protected Tournament $tournament;
    protected array $participants;
    protected ?string $format;
    protected array $settings;

    public function __construct(Tournament $tournament)
    {
        $this->tournament = $tournament;
        $this->format = $tournament->format ?? 'team';
        $this->settings = $tournament->bracket_settings ?? [];
    }

    /**
     * Generate bracket based on tournament type
     */
    public function generateBracket(array $participants, string $bracketType = 'winners'): Bracket
    {
        $this->participants = $participants;
        
        // Create bracket
        $bracket = Bracket::create([
            'tournament_id' => $this->tournament->id,
            'name' => $this->getBracketName($bracketType),
            'type' => $bracketType,
            'rounds' => 0,
            'structure' => [],
            'seeding' => [],
            'is_active' => true,
        ]);

        // Apply intelligent seeding
        $seededParticipants = $this->applySeeding($participants);

        // Generate matches based on tournament type
        switch ($this->tournament->type) {
            case 'knockout':
            case 'elimination':
                $this->generateSingleElimination($bracket, $seededParticipants);
                break;
            case 'double-elimination':
                $this->generateDoubleElimination($bracket, $seededParticipants);
                break;
            case 'round-robin':
                $this->generateRoundRobin($bracket, $seededParticipants);
                break;
            case 'group-knockout':
                $this->generateGroupKnockout($bracket, $seededParticipants);
                break;
            case 'swiss_system':
                $this->generateSwissSystem($bracket, $seededParticipants);
                break;
        }

        return $bracket->fresh(['gameMatches']);
    }
}
```

### Seeding Algorithms
```php
/**
 * Apply intelligent seeding based on rankings, ratings, or random
 */
protected function applySeeding(array $participants): array
{
    $seedingMethod = $this->settings['seeding_method'] ?? 'random';
    
    switch ($seedingMethod) {
        case 'ranking':
            return $this->seedByRanking($participants);
        case 'rating':
            return $this->seedByRating($participants);
        case 'balanced':
            return $this->seedBalanced($participants);
        case 'random':
        default:
            return $this->seedRandom($participants);
    }
}

/**
 * Balanced seeding to avoid early matchups of top seeds
 */
protected function seedBalanced(array $participants): array
{
    $count = count($participants);
    $seeded = array_fill(0, $count, null);
    
    // Place top seeds in strategic positions
    $topSeeds = array_slice($participants, 0, min(8, $count));
    $positions = $this->getBalancedPositions($count);
    
    foreach ($topSeeds as $index => $participant) {
        $seeded[$positions[$index]] = $participant;
    }
    
    // Fill remaining positions with other participants
    $remaining = array_slice($participants, count($topSeeds));
    $remainingIndex = 0;
    
    for ($i = 0; $i < $count; $i++) {
        if ($seeded[$i] === null) {
            $seeded[$i] = $remaining[$remainingIndex] ?? null;
            $remainingIndex++;
        }
    }
    
    return array_filter($seeded);
}
```

### Bracket Generation Algorithms
```php
/**
 * Generate single elimination bracket
 */
protected function generateSingleElimination(Bracket $bracket, array $participants): void
{
    $participantCount = count($participants);
    $rounds = ceil(log($participantCount, 2));
    $totalMatches = $participantCount - 1;
    
    // Calculate byes for first round
    $powerOfTwo = pow(2, $rounds);
    $byes = $powerOfTwo - $participantCount;
    
    $this->createSingleEliminationMatches($bracket, $participants, $rounds, $byes);
    
    $bracket->update([
        'rounds' => $rounds,
        'structure' => [
            'type' => 'single_elimination',
            'total_participants' => $participantCount,
            'total_matches' => $totalMatches,
            'rounds' => $rounds,
            'byes' => $byes,
            'power_of_two' => $powerOfTwo,
        ],
        'seeding' => [
            'method' => $this->settings['seeding_method'] ?? 'random',
            'participants' => $participants,
        ],
    ]);
}
```

## 10.3 Payment Processing

### MpesaService
```php
class MpesaService
{
    protected $consumerKey;
    protected $consumerSecret;
    protected $baseUrl;
    protected $passkey;
    protected $shortcode;
    protected $callbackUrl;
    
    public function __construct()
    {
        $this->consumerKey = config('services.mpesa.consumer_key');
        $this->consumerSecret = config('services.mpesa.consumer_secret');
        $this->baseUrl = config('services.mpesa.base_url');
        $this->passkey = config('services.mpesa.passkey');
        $this->shortcode = config('services.mpesa.shortcode');
        $this->callbackUrl = config('services.mpesa.callback_url');
    }
    
    /**
     * Generate access token for M-Pesa API
     */
    public function generateAccessToken(): ?string
    {
        try {
            $credentials = base64_encode($this->consumerKey . ':' . $this->consumerSecret);
            
            $response = Http::withOptions(['verify' => false])
                ->withHeaders([
                    'Authorization' => 'Basic ' . $credentials,
                    'Content-Type' => 'application/json',
                ])
                ->get($this->baseUrl . '/oauth/v1/generate?grant_type=client_credentials');
            
            if ($response->successful()) {
                return $response->json()['access_token'];
            }
            
            Log::error('M-Pesa Access Token Error: ' . $response->body());
            return null;
        } catch (\Exception $e) {
            Log::error('M-Pesa Access Token Exception: ' . $e->getMessage());
            return null;
        }
    }
}
```

### Payment Workflow
```php
/**
 * Create payment record and initiate payment
 */
public function createPayment(User $user, float $amount, ?Team $team = null, string $description = 'Tournament Registration', ?string $phoneNumber = null): array
{
    try {
        // Create payment record
        $payment = Payment::create([
            'user_id' => $user->id,
            'team_id' => $team?->id,
            'payment_method' => 'mpesa',
            'amount' => $amount,
            'currency' => 'KES',
            'reference_number' => uniqid('PAY_'),
            'description' => $description,
            'status' => 'pending',
        ]);
        
        // Use provided phone number or fall back to user's phone
        $phone = $phoneNumber ?: $user->phone;
        
        if (!$phone) {
            throw new \Exception('Phone number is required for M-Pesa payment');
        }
        
        // Initiate STK Push
        $stkResult = $this->stkPush(
            $phone,
            $amount,
            $payment->reference_number,
            $description
        );
        
        if ($stkResult['success']) {
            $payment->update([
                'checkout_request_id' => $stkResult['checkout_request_id'],
                'merchant_request_id' => $stkResult['merchant_request_id'],
                'status' => 'processing',
            ]);
            
            return [
                'success' => true,
                'payment' => $payment,
                'message' => $stkResult['customer_message'],
            ];
        }
        
        $payment->markAsFailed($stkResult['message']);
        return $stkResult;
        
    } catch (\Exception $e) {
        Log::error('Create Payment Exception: ' . $e->getMessage());
        return ['success' => false, 'message' => 'Payment creation failed'];
    }
}
```

## 10.4 Email Services

### EmailSettingsService
```php
class EmailSettingsService
{
    /**
     * Get active email configuration
     */
    public function getActiveEmailConfig(): ?EmailCredential
    {
        return EmailCredential::where('is_active', true)->first();
    }
    
    /**
     * Test email configuration
     */
    public function testEmailConfiguration(EmailCredential $emailCredential): array
    {
        try {
            // Set temporary mail configuration
            config([
                'mail.mailers.smtp.host' => $emailCredential->smtp_host,
                'mail.mailers.smtp.port' => $emailCredential->smtp_port,
                'mail.mailers.smtp.username' => $emailCredential->smtp_username,
                'mail.mailers.smtp.password' => $emailCredential->smtp_password,
                'mail.mailers.smtp.encryption' => $emailCredential->smtp_encryption,
                'mail.from.address' => $emailCredential->from_email,
                'mail.from.name' => $emailCredential->from_name,
            ]);
            
            // Send test email
            Mail::raw('This is a test email from the tournament management system.', function ($message) use ($emailCredential) {
                $message->to($emailCredential->from_email)
                        ->subject('Test Email Configuration');
            });
            
            return ['success' => true, 'message' => 'Email configuration test successful'];
            
        } catch (\Exception $e) {
            return ['success' => false, 'message' => 'Email configuration test failed: ' . $e->getMessage()];
        }
    }
}
```

### Email Notification System
```php
// Email notification classes
class TeamRegistrationNotification extends Notification
{
    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->subject('Team Registration Confirmation')
            ->greeting('Hello ' . $notifiable->name)
            ->line('Your team has been successfully registered for the tournament.')
            ->line('Team: ' . $this->team->name)
            ->line('Tournament: ' . $this->tournament->name)
            ->action('View Tournament Details', $this->tournamentUrl)
            ->line('Thank you for participating!');
    }
}

class PaymentConfirmationNotification extends Notification
{
    public function toMail($notifiable)
    {
        return (new MailMessage)
            ->subject('Payment Confirmation')
            ->greeting('Hello ' . $notifiable->name)
            ->line('Your payment has been successfully processed.')
            ->line('Amount: KES ' . number_format($this->payment->amount, 2))
            ->line('Reference: ' . $this->payment->reference_number)
            ->line('Thank you for your payment!');
    }
}
```

## 10.5 OTP System

### OtpService
```php
class OtpService
{
    /**
     * Generate and send OTP to team player
     */
    public function sendPlayerOtp(Player $player): bool
    {
        try {
            $otp = $player->generateOtp();
            
            // Send email with OTP
            Mail::send('emails.player-otp', [
                'player' => $player,
                'otp' => $otp,
                'team' => $player->team,
            ], function ($message) use ($player) {
                $message->from(config('mail.from.address'), config('mail.from.name'));
                $message->to($player->email, $player->name)
                        ->subject('Team Registration - Verify Your Email');
            });
            
            Log::info("OTP sent to player: {$player->email}");
            return true;
            
        } catch (\Exception $e) {
            Log::error("Failed to send OTP to player {$player->email}: " . $e->getMessage());
            return false;
        }
    }
    
    /**
     * Send OTPs to all team members
     */
    public function sendTeamOtps(\App\Models\Team $team): array
    {
        $results = [
            'players' => ['sent' => 0, 'failed' => 0],
            'officials' => ['sent' => 0, 'failed' => 0],
        ];
        
        // Send OTPs to players
        foreach ($team->teamPlayers as $player) {
            if ($this->sendPlayerOtp($player)) {
                $results['players']['sent']++;
            } else {
                $results['players']['failed']++;
            }
        }
        
        // Send OTPs to officials
        foreach ($team->teamOfficials as $official) {
            if ($this->sendOfficialOtp($official)) {
                $results['officials']['sent']++;
            } else {
                $results['officials']['failed']++;
            }
        }
        
        return $results;
    }
}
```

### OTP Verification
```php
/**
 * Check if all team members have verified their OTPs
 */
public function isTeamFullyVerified(\App\Models\Team $team): bool
{
    $unverifiedPlayers = $team->teamPlayers()->where('otp_verified', false)->count();
    $unverifiedOfficials = $team->teamOfficials()->where('otp_verified', false)->count();
    
    return $unverifiedPlayers === 0 && $unverifiedOfficials === 0;
}

/**
 * Get team verification status
 */
public function getTeamVerificationStatus(\App\Models\Team $team): array
{
    $totalPlayers = $team->teamPlayers()->count();
    $verifiedPlayers = $team->teamPlayers()->where('otp_verified', true)->count();
    
    $totalOfficials = $team->teamOfficials()->count();
    $verifiedOfficials = $team->teamOfficials()->where('otp_verified', true)->count();
    
    return [
        'players' => [
            'total' => $totalPlayers,
            'verified' => $verifiedPlayers,
            'pending' => $totalPlayers - $verifiedPlayers,
        ],
        'officials' => [
            'total' => $totalOfficials,
            'verified' => $verifiedOfficials,
            'pending' => $totalOfficials - $verifiedOfficials,
        ],
        'is_fully_verified' => $this->isTeamFullyVerified($team),
    ];
}
```

## 10.6 Data Scoping

### DataScopingService
```php
class DataScopingService
{
    /**
     * Scope tournaments based on user role
     */
    public function scopeTournaments(Builder $query, User $user): Builder
    {
        $userRoles = $user->roles()->pluck('name')->toArray();

        // Admins can see all tournaments
        if (in_array('admin', $userRoles) || in_array('super_admin', $userRoles)) {
            return $query;
        }

        // Organizers can see tournaments they manage
        if (in_array('organizer', $userRoles)) {
            return $query->where('organizer_id', $user->id);
        }

        // Referees can see tournaments they're assigned to
        if (in_array('referee', $userRoles)) {
            return $query->whereHas('matches', function($q) use ($user) {
                $q->where('referee_id', $user->id);
            });
        }

        // Players can see tournaments they're participating in
        if (in_array('player', $userRoles)) {
            $player = Player::where('user_id', $user->id)->first();
            if ($player) {
                return $query->whereHas('teams.players', function($q) use ($player) {
                    $q->where('player_id', $player->id);
                });
            }
        }

        return $query->where('id', 0);
    }
    
    /**
     * Scope matches based on user role
     */
    public function scopeMatches(Builder $query, User $user): Builder
    {
        $userRoles = $user->roles()->pluck('name')->toArray();

        // Admins can see all matches
        if (in_array('admin', $userRoles) || in_array('super_admin', $userRoles)) {
            return $query;
        }

        // Organizers can see matches in their tournaments
        if (in_array('organizer', $userRoles)) {
            return $query->whereHas('tournament', function($q) use ($user) {
                $q->where('organizer_id', $user->id);
            });
        }

        // Referees can see matches they're assigned to
        if (in_array('referee', $userRoles)) {
            return $query->where('referee_id', $user->id);
        }

        // Players can see matches they're participating in
        if (in_array('player', $userRoles)) {
            $player = Player::where('user_id', $user->id)->first();
            if ($player) {
                return $query->where(function($q) use ($player) {
                    $q->where('player1_id', $player->id)
                      ->orWhere('player2_id', $player->id)
                      ->orWhereHas('team1.players', function($q) use ($player) {
                          $q->where('player_id', $player->id);
                      })
                      ->orWhereHas('team2.players', function($q) use ($player) {
                          $q->where('player_id', $player->id);
                      });
                });
            }
        }

        return $query->where('id', 0);
    }
}
```

---

## Service Integration

### Service Dependencies
```
TournamentBracketService
├── Tournament Model
├── Bracket Model
├── GameMatch Model
└── Team/Player Models

MpesaService
├── Payment Model
├── User Model
└── Team Model

OtpService
├── Player Model
├── TeamOfficial Model
└── User Model

TeamRegistrationService
├── Team Model
├── Player Model
├── TeamOfficial Model
├── Tournament Model
└── User Model
```

### Service Usage Examples
```php
// Tournament bracket generation
$bracketService = new TournamentBracketService($tournament);
$bracket = $bracketService->generateBracket($participants, 'winners');

// Payment processing
$mpesaService = new MpesaService();
$payment = $mpesaService->createPayment($user, $amount, $team);

// OTP verification
$otpService = new OtpService();
$otpService->sendPlayerOtp($player);

// Team registration
$registrationService = new TeamRegistrationService();
$result = $registrationService->registerTeamForTournament($data, $tournament);
```

---

## Next Steps

- [API Documentation](05_API_Documentation.md) - API usage and endpoints
- [Security](11_Security.md) - Security implementation
- [Database](12_Database.md) - Database schema and relationships
- [User Guide](17_User_Guide.md) - User documentation
