<?php

namespace App\Repos;

use App\Models\User;
use Illuminate\Support\Carbon;

class UserRepo
{
    public static function create(array $user)
    {
        return User::create($user);
    }

    public static function read(int $id)
    {
        return User::with(['plan'])->find($id);
    }

    public static function firstByEmailOrFail(string $email)
    {
        return User::whereEmail($email)->firstOrFail();
    }

    public static function firstByVerifyTokenAndOtpOrFail(string $token, int $otp)
    {
        return User::whereVerifyToken($token)
            ->whereOtp($otp)
            ->firstOrFail();
    }

    public static function firstByAuthToken(string $token)
    {
        return User::whereAuthToken($token)->first();
    }

    public static function findByIdOrFail(int $id)
    {
        return User::findOrFail($id);
    }

    public static function updateByIdOrFail(int $id, array $data)
    {
        $user = User::findOrFail($id);
        $user->update($data);
        return $user->fresh();
    }

    public static function paginate(int $page, string|null $search)
    {
        $query = User::with(['plan'])->excludeAdmin();
        if ($search) {
            $query = $query->where(function ($query) use ($search) {
                $query->where('name', 'like', "%$search%")
                    ->orWhere('email', 'like', "%$search%")
                    ->orWhere('stripe_id', 'like', "%$search%")
                    ->orWhereHas('plan', function ($planQuery) use ($search) {
                        $planQuery->where('title', 'like', "%$search%");
                    });
            });
        } else {
            $query = $query->latest();
        }
        return $query->paginate(18, ['*'], 'page', $page);
    }

    public static function toggleBlockedOrFail(int $id)
    {
        $user = User::findOrFail($id);
        return $user->update(['blocked' => !$user->blocked]);
    }

    public static function countUsers()
    {
        return User::excludeAdmin()->count();
    }

    public static function countUsersBetweenDate(Carbon $start, Carbon $end)
    {
        return User::excludeAdmin()
            ->whereBetween('created_at', [$start, $end])
            ->count();
    }

    public static function dailyUsersCountBetweenDate(Carbon $start, Carbon $end)
    {
        return User::excludeAdmin()
            ->dailyCountBetweenDate($start, $end)
            ->get();
    }

    public static function clearOtpOrFail(int $id)
    {
        return User::findOrFail($id)->update(['otp' => null]);
    }

    public static function updateOtpOrFail(int $id, int $otp)
    {
        $user = User::findOrFail($id);
        $user->update(['otp' => $otp]);
        return $user->fresh();
    }

    public static function findByStripeIdOrFail(string $stripeId)
    {
        return User::where('stripe_id', $stripeId)->firstOrFail();
    }

    public static function existAdmin()
    {
        return User::where('admin', true)->exists();
    }
}
