<?php
declare(strict_types=1);

namespace App\Modules\TrainingGroups\Services;

use App\Core\App;

class AutoAssignmentService
{
    /**
     * Attempt to auto-assign a player to a training group.
     *
     * @param int   $playerId
     * @param int   $disciplineId
     * @param int   $levelId
     * @param array $preferences ['day_of_week' => int|null, 'time' => 'AM'|'PM'|null, 'enrollment_id' => int]
     * @return array ['status' => 'assigned'|'waiting_list', 'group_id' => int|null, 'waiting_list_id' => int|null]
     */
    public static function assign(int $playerId, int $disciplineId, int $levelId, array $preferences = []): array
    {
        $db = App::getInstance()->db();

        // 1. Get player's age and gender
        $player = $db->selectOne(
            "SELECT date_of_birth, gender FROM players WHERE id = ?",
            [$playerId]
        );

        $playerAge = null;
        if (!empty($player['date_of_birth'])) {
            $dob = new \DateTime($player['date_of_birth']);
            $now = new \DateTime();
            $playerAge = (int) $now->diff($dob)->y;
        }
        $playerGender = $player['gender'] ?? null;

        // 2. Query available training groups
        $groups = $db->select(
            "SELECT tg.*
             FROM training_groups tg
             INNER JOIN academies a ON a.id = tg.academy_id
             WHERE a.discipline_id = ?
               AND tg.level_id = ?
               AND tg.is_active = 1
               AND tg.is_full = 0
               AND tg.is_archived = 0",
            [$disciplineId, $levelId]
        );

        // 3. Filter by age and gender
        $eligible = [];
        foreach ($groups as $group) {
            // Filter by gender restriction
            if (!empty($group['gender_restriction']) && $playerGender !== null) {
                if ($group['gender_restriction'] !== $playerGender) {
                    continue;
                }
            }

            // Filter by age range
            if ($playerAge !== null) {
                if ($group['age_from'] !== null && $playerAge < (int) $group['age_from']) {
                    continue;
                }
                if ($group['age_to'] !== null && $playerAge > (int) $group['age_to']) {
                    continue;
                }
            }

            // 5. Filter by time preference (AM/PM)
            if (!empty($preferences['time']) && !empty($group['start_time'])) {
                $startHour = (int) substr($group['start_time'], 0, 2);
                if ($preferences['time'] === 'AM' && $startHour >= 12) {
                    continue;
                }
                if ($preferences['time'] === 'PM' && $startHour < 12) {
                    continue;
                }
            }

            $eligible[] = $group;
        }

        // 6. Score groups
        $scored = [];
        foreach ($eligible as $group) {
            $score = 0;

            // +10 for age match (player age within range)
            if ($playerAge !== null && $group['age_from'] !== null && $group['age_to'] !== null) {
                if ($playerAge >= (int) $group['age_from'] && $playerAge <= (int) $group['age_to']) {
                    $score += 10;
                }
            }

            // +5 for day match
            if (isset($preferences['day_of_week']) && $group['day_of_week'] !== null) {
                if ((int) $preferences['day_of_week'] === (int) $group['day_of_week']) {
                    $score += 5;
                }
            }

            // +3 for capacity 60-80% (social density)
            $maxCap = (int) $group['max_capacity'];
            $currentCount = (int) $group['current_count'];
            if ($maxCap > 0) {
                $occupancy = $currentCount / $maxCap;
                if ($occupancy >= 0.6 && $occupancy <= 0.8) {
                    $score += 3;
                }
            }

            $scored[] = [
                'group' => $group,
                'score' => $score,
            ];
        }

        // 7. Sort by score DESC
        usort($scored, fn($a, $b) => $b['score'] <=> $a['score']);

        // Assign to top group
        if (!empty($scored)) {
            $bestGroup = $scored[0]['group'];
            $groupId = (int) $bestGroup['id'];
            $enrollmentId = (int) ($preferences['enrollment_id'] ?? 0);

            // Create group_membership
            $db->insert('group_memberships', [
                'group_id'      => $groupId,
                'enrollment_id' => $enrollmentId,
                'player_id'     => $playerId,
                'joined_at'     => date('Y-m-d H:i:s'),
                'status'        => 'active',
            ]);

            // Update current_count
            $newCount = (int) $bestGroup['current_count'] + 1;
            $isFull = $newCount >= (int) $bestGroup['max_capacity'] ? 1 : 0;
            $db->update('training_groups', [
                'current_count' => $newCount,
                'is_full'       => $isFull,
            ], 'id = ?', [$groupId]);

            return [
                'status'   => 'assigned',
                'group_id' => $groupId,
                'waiting_list_id' => null,
            ];
        }

        // 8. No group found — add to waiting list
        $db->insert('waiting_list', [
            'player_id'            => $playerId,
            'discipline_id'        => $disciplineId,
            'level_id'             => $levelId,
            'preferred_day_of_week'=> $preferences['day_of_week'] ?? null,
            'preferred_time'       => $preferences['time'] ?? null,
            'priority'             => 100,
            'requested_group_type' => $preferences['group_type'] ?? null,
            'status'               => 'waiting',
        ]);

        $waitingListId = (int) $db->selectOne(
            "SELECT id FROM waiting_list WHERE player_id = ? AND discipline_id = ? AND status = 'waiting' ORDER BY id DESC LIMIT 1",
            [$playerId, $disciplineId]
        )['id'];

        return [
            'status'          => 'waiting_list',
            'group_id'        => null,
            'waiting_list_id' => $waitingListId,
        ];
    }
}
