<?php
declare(strict_types=1);

namespace App\Modules\Achievements\Models;

use App\Core\Model;
use App\Core\App;

class PlayerAchievement extends Model
{
    protected static string $table = 'player_achievements';
    protected static string $primaryKey = 'id';
    protected static bool $timestamps = true;
    protected static bool $softDelete = false;
    protected static bool $autoTrackAuthor = false;

    protected static array $fillable = [
        'player_id',
        'achievement_id',
        'earned_at',
        'context_json',
        'points_earned',
        'notified',
    ];

    /**
     * Get all achievements for a player with definition details.
     */
    public static function getForPlayer(int $playerId): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT pa.*, ad.code, ad.name_ar, ad.name_en, ad.description_ar,
                    ad.category, ad.icon, ad.badge_color, ad.discipline_id,
                    sd.name_ar AS discipline_name
             FROM player_achievements pa
             INNER JOIN achievement_definitions ad ON ad.id = pa.achievement_id
             LEFT JOIN sport_disciplines sd ON sd.id = ad.discipline_id
             WHERE pa.player_id = ?
             ORDER BY pa.earned_at DESC",
            [$playerId]
        );
    }

    /**
     * Get total points for a player.
     */
    public static function getTotalPoints(int $playerId): int
    {
        $db = App::getInstance()->db();
        $row = $db->selectOne(
            "SELECT COALESCE(SUM(points_earned), 0) as total FROM player_achievements WHERE player_id = ?",
            [$playerId]
        );
        return (int) ($row['total'] ?? 0);
    }

    /**
     * Check if a player has already earned a specific achievement.
     */
    public static function hasEarned(int $playerId, int $achievementId): bool
    {
        $db = App::getInstance()->db();
        $row = $db->selectOne(
            "SELECT id FROM player_achievements WHERE player_id = ? AND achievement_id = ?",
            [$playerId, $achievementId]
        );
        return $row !== null;
    }

    /**
     * Get recent achievements across all players.
     */
    public static function getRecent(int $limit = 20): array
    {
        $db = App::getInstance()->db();
        return $db->select(
            "SELECT pa.*, ad.name_ar AS achievement_name, ad.icon, ad.badge_color, ad.category,
                    p.full_name_ar AS player_name, p.registration_serial
             FROM player_achievements pa
             INNER JOIN achievement_definitions ad ON ad.id = pa.achievement_id
             INNER JOIN players p ON p.id = pa.player_id
             ORDER BY pa.earned_at DESC
             LIMIT ?",
            [$limit]
        );
    }

    /**
     * Get achievement count per player for leaderboard.
     */
    public static function getLeaderboard(?int $disciplineId = null, int $limit = 50): array
    {
        $db = App::getInstance()->db();

        $join = '';
        $where = 'WHERE 1=1';
        $params = [];

        if ($disciplineId !== null) {
            $join = 'INNER JOIN achievement_definitions ad ON ad.id = pa.achievement_id';
            $where .= ' AND (ad.discipline_id = ? OR ad.discipline_id IS NULL)';
            $params[] = $disciplineId;
        }

        $params[] = $limit;

        return $db->select(
            "SELECT pa.player_id, p.full_name_ar AS player_name, p.registration_serial,
                    p.photo_path,
                    SUM(pa.points_earned) AS total_points,
                    COUNT(pa.id) AS total_achievements
             FROM player_achievements pa
             INNER JOIN players p ON p.id = pa.player_id AND p.is_archived = 0
             {$join}
             {$where}
             GROUP BY pa.player_id, p.full_name_ar, p.registration_serial, p.photo_path
             ORDER BY total_points DESC
             LIMIT ?",
            $params
        );
    }

    /**
     * Get context decoded from JSON.
     */
    public function getContext(): array
    {
        $raw = $this->context_json;
        if (empty($raw)) {
            return [];
        }
        $decoded = json_decode($raw, true);
        return is_array($decoded) ? $decoded : [];
    }
}
