<?php

namespace App\Repositories;

use App\Interfaces\UserRepositoryInterface;
use App\Models\User;
use App\Models\UserPoint;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Pagination\LengthAwarePaginator;
use Illuminate\Support\Str;

class UserRepository implements UserRepositoryInterface
{
    public function __construct(
        private readonly User $model,
        private readonly UserPoint $pointModel
    ) {}

    public function findById(int $id): ?User
    {
        return $this->model->with('favoriteTeam', 'badges')->find($id);
    }

    public function findByEmail(string $email): ?User
    {
        return $this->model->where('email', $email)->first();
    }

    public function findByGoogleId(string $googleId): ?User
    {
        return $this->model->where('google_id', $googleId)->first();
    }

    public function create(array $data): User
    {
        return $this->model->create($data);
    }

    public function update(int $id, array $data): bool
    {
        return $this->model->where('id', $id)->update($data) > 0;
    }

    public function getLeaderboard(int $limit = 50): Collection
    {
        return $this->model
            ->with('favoriteTeam')
            ->where('is_banned', false)
            ->where('is_anonymized', false)
            ->where('is_admin', false)   // admins don't appear on the leaderboard
            ->orderByDesc('total_points')
            ->limit($limit)
            ->get();
    }

    /**
     * Paginated user list for the admin panel, with optional name/email search.
     */
    public function paginate(int $perPage = 30, ?string $search = null): LengthAwarePaginator
    {
        return $this->model
            ->with('favoriteTeam')
            ->when($search, function ($query, $search) {
                $query->where(function ($q) use ($search) {
                    $q->where('name', 'like', "%{$search}%")
                      ->orWhere('email', 'like', "%{$search}%")
                      ->orWhere('username', 'like', "%{$search}%");
                });
            })
            ->orderByDesc('created_at')
            ->paginate($perPage)
            ->withQueryString();
    }

    public function awardPoints(int $userId, int $points, string $reason, ?object $pointable = null): void
    {
        $data = [
            'user_id' => $userId,
            'points'  => $points,
            'reason'  => $reason,
        ];

        if ($pointable) {
            $data['pointable_type'] = get_class($pointable);
            $data['pointable_id']   = $pointable->id;
        }

        $this->pointModel->create($data);

        // Update the cached total on the user row
        $this->model->where('id', $userId)->increment('total_points', $points);

        $this->updateFanLevel($userId);
    }

    public function updateFanLevel(int $userId): void
    {
        $user = $this->model->find($userId);
        if (! $user) {
            return;
        }

        $level = match (true) {
            $user->total_points >= 500 => 4,  // Legend
            $user->total_points >= 200 => 3,  // Superfan
            $user->total_points >= 50  => 2,  // Fan
            default                    => 1,  // Rookie
        };

        $this->model->where('id', $userId)->update(['fan_level' => $level]);
    }

    public function recordCheckin(int $userId): void
    {
        $user = $this->model->find($userId);
        if (! $user) {
            return;
        }

        $today     = today();
        $lastDate  = $user->last_checkin_date;

        if ($lastDate && $lastDate->isToday()) {
            return; // Already checked in today
        }

        $streak = ($lastDate && $lastDate->isYesterday())
            ? $user->streak_days + 1
            : 1; // Reset streak if gap > 1 day

        $this->model->where('id', $userId)->update([
            'streak_days'       => $streak,
            'last_checkin_date' => $today,
        ]);
    }

    /**
     * Anonymize a user's personal data while preserving their stats,
     * predictions, poll votes, and leaderboard standing (Google Play
     * data-deletion compliant "soft delete").
     *
     * - email     -> Anonymous_{id}@matchday.com
     * - name      -> "Anonymous Fan"
     * - username  -> anon_{id}
     * - avatar, device token, google_id -> null
     * - All Sanctum tokens revoked
     * - total_points / predictions / poll_votes / badges: UNTOUCHED
     */
    public function anonymize(int $userId): void
    {
        $user = $this->model->find($userId);
        if (! $user) {
            return;
        }

        $user->forceFill([
            'name'          => 'Anonymous Fan',
            'username'      => 'anon_' . $user->id . '_' . Str::random(4),
            'email'         => "Anonymous_{$user->id}@matchday.com",
            'google_id'     => null,
            'avatar_url'    => null,
            'device_token'  => null,
            'password'      => null,
            'is_anonymized' => true,
        ])->save();

        // Revoke all access tokens — account can no longer be signed into
        $user->tokens()->delete();
    }
}
