<?php
declare(strict_types=1);

namespace App\Modules\PlayerAffairs\Services;

use App\Core\App;
use App\Core\EventBus;
use App\Modules\PlayerAffairs\Models\EvaluationCriterion;
use App\Modules\PlayerAffairs\Models\PlayerEvaluation;

class EvaluationService
{
    /**
     * Submit a new player evaluation.
     *
     * @param array $data Expected keys: player_id, discipline_id, session_id, evaluator_coach_id,
     *                     evaluation_date, scores (array of [{criterion_id, score, notes}]),
     *                     strengths_ar, weaknesses_ar, coach_notes, parent_visible
     * @return array The created evaluation record
     */
    public static function submitEvaluation(array $data): array
    {
        $db = App::getInstance()->db();

        $playerId = (int) ($data['player_id'] ?? 0);
        $disciplineId = (int) ($data['discipline_id'] ?? 0);
        $scores = $data['scores'] ?? [];

        // Calculate overall score from scores using criteria weights
        $overallScore = PlayerEvaluation::calculateOverallScore($scores, $disciplineId);

        // Determine skill level based on overall score
        $skillLevel = self::determineSkillLevel($overallScore);

        // Suggest a group
        $suggestedGroup = self::suggestGroup($playerId, $skillLevel, $disciplineId);

        $evaluationData = [
            'player_id'              => $playerId,
            'discipline_id'          => $disciplineId,
            'session_id'             => !empty($data['session_id']) ? (int) $data['session_id'] : null,
            'evaluator_coach_id'     => !empty($data['evaluator_coach_id']) ? (int) $data['evaluator_coach_id'] : null,
            'evaluation_date'        => $data['evaluation_date'] ?? date('Y-m-d'),
            'overall_score'          => (string) $overallScore,
            'skill_level'            => $skillLevel,
            'recommended_group_type' => $suggestedGroup['group_type'] ?? null,
            'recommended_group_id'   => $suggestedGroup['group_id'] ?? null,
            'scores_json'            => json_encode($scores, JSON_UNESCAPED_UNICODE),
            'strengths_ar'           => $data['strengths_ar'] ?? null,
            'weaknesses_ar'          => $data['weaknesses_ar'] ?? null,
            'coach_notes'            => $data['coach_notes'] ?? null,
            'parent_visible'         => (int) ($data['parent_visible'] ?? 1),
            'status'                 => 'submitted',
        ];

        $evaluation = PlayerEvaluation::create($evaluationData);

        EventBus::dispatch('player.evaluation_submitted', [
            'evaluation_id' => (int) $evaluation->id,
            'player_id'     => $playerId,
            'discipline_id' => $disciplineId,
            'overall_score' => $overallScore,
            'skill_level'   => $skillLevel,
        ]);

        return $evaluation->toArray();
    }

    /**
     * Approve an evaluation.
     */
    public static function approveEvaluation(int $evalId, int $approvedBy): bool
    {
        $evaluation = PlayerEvaluation::findOrFail($evalId);

        $evaluation->update([
            'status'      => 'approved',
            'approved_by' => $approvedBy,
            'approved_at' => date('Y-m-d H:i:s'),
        ]);

        EventBus::dispatch('player.evaluation_approved', [
            'evaluation_id' => $evalId,
            'player_id'     => (int) $evaluation->player_id,
            'discipline_id' => (int) $evaluation->discipline_id,
            'approved_by'   => $approvedBy,
        ]);

        return true;
    }

    /**
     * Get the progression history for a player in a specific discipline.
     * Returns evaluations over time for charting.
     */
    public static function getProgressionHistory(int $playerId, int $disciplineId): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT pe.id, pe.evaluation_date, pe.overall_score, pe.skill_level,
                    pe.scores_json, pe.status, c.full_name_ar AS coach_name
             FROM player_evaluations pe
             LEFT JOIN coaches c ON c.id = pe.evaluator_coach_id
             WHERE pe.player_id = ? AND pe.discipline_id = ?
             ORDER BY pe.evaluation_date ASC, pe.id ASC",
            [$playerId, $disciplineId]
        );
    }

    /**
     * Suggest a training group based on player skill level, discipline, age, and gender.
     *
     * @return array ['group_id' => int|null, 'group_type' => string|null, 'group_name' => string|null]
     */
    public static function suggestGroup(int $playerId, string $skillLevel, int $disciplineId): array
    {
        $db = App::getInstance()->db();

        // Get player info
        $player = $db->selectOne(
            "SELECT date_of_birth, gender FROM players WHERE id = ?",
            [$playerId]
        );

        if (!$player) {
            return ['group_id' => null, 'group_type' => null, 'group_name' => null];
        }

        // Calculate age
        $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;

        // Map skill level to potential level names (look for level containing the skill_level keyword)
        $levelKeywords = [
            'beginner'     => ['مبتدئ', 'beginner', 'level_1', 'level 1'],
            'intermediate' => ['متوسط', 'intermediate', 'level_2', 'level 2'],
            'advanced'     => ['متقدم', 'advanced', 'level_3', 'level 3'],
            'elite'        => ['نخبة', 'elite', 'level_4', 'level 4', 'professional'],
        ];

        $keywords = $levelKeywords[$skillLevel] ?? [];

        // Find matching groups
        $sql = "SELECT tg.*, a.name_ar AS academy_name, al.name_ar AS level_name
                FROM training_groups tg
                INNER JOIN academies a ON a.id = tg.academy_id
                LEFT JOIN academy_levels al ON al.id = tg.level_id
                WHERE a.discipline_id = ?
                  AND tg.is_active = 1
                  AND tg.is_full = 0
                  AND tg.is_archived = 0
                ORDER BY tg.current_count ASC";

        $groups = $db->select($sql, [$disciplineId]);

        // Score groups by fit
        $bestGroup = null;
        $bestScore = -1;

        foreach ($groups as $group) {
            $score = 0;

            // Gender match
            if (!empty($group['gender_restriction']) && $playerGender !== null) {
                if ($group['gender_restriction'] !== $playerGender) {
                    continue; // Skip incompatible gender
                }
                $score += 5;
            }

            // Age match
            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;
                }
                $score += 5;
            }

            // Level name match
            $levelName = strtolower(($group['level_name'] ?? '') . ' ' . ($group['name_ar'] ?? ''));
            foreach ($keywords as $keyword) {
                if (mb_strpos($levelName, $keyword) !== false) {
                    $score += 10;
                    break;
                }
            }

            if ($score > $bestScore) {
                $bestScore = $score;
                $bestGroup = $group;
            }
        }

        if ($bestGroup) {
            return [
                'group_id'   => (int) $bestGroup['id'],
                'group_type' => $bestGroup['group_type'] ?? null,
                'group_name' => $bestGroup['name_ar'] ?? null,
            ];
        }

        return ['group_id' => null, 'group_type' => null, 'group_name' => null];
    }

    /**
     * Determine skill level from overall score.
     */
    public static function determineSkillLevel(float $overallScore): string
    {
        if ($overallScore >= 8.0) {
            return 'elite';
        } elseif ($overallScore >= 6.0) {
            return 'advanced';
        } elseif ($overallScore >= 3.0) {
            return 'intermediate';
        }
        return 'beginner';
    }
}
