<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\MorphTo;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Str;

class ApiToken extends Model
{
    use HasFactory;

    protected $fillable = [
        'tokenable_type',
        'tokenable_id',
        'name',
        'token',
        'plain_token',
        'abilities',
        'ip_whitelist',
        'last_used_at',
        'expires_at',
        'is_active',
    ];

    protected $casts = [
        'abilities' => 'array',
        'ip_whitelist' => 'array',
        'last_used_at' => 'datetime',
        'expires_at' => 'datetime',
        'is_active' => 'boolean',
        'plain_token' => 'encrypted',
    ];

    protected $hidden = [
        'token',
    ];

    /**
     * Get the tokenable entity (User or Reseller)
     */
    public function tokenable(): MorphTo
    {
        return $this->morphTo();
    }

    /**
     * Get all API requests for this token
     */
    public function requests(): HasMany
    {
        return $this->hasMany(ApiRequest::class);
    }

    /**
     * Generate a new API token
     */
    public static function generateToken(): string
    {
        return 'pdns_' . Str::random(40);
    }

    /**
     * Hash the token for storage
     */
    public static function hashToken(string $token): string
    {
        return hash('sha256', $token);
    }

    /**
     * Check if token has a specific ability
     */
    public function can(string $ability): bool
    {
        if (empty($this->abilities)) {
            return false;
        }

        // Check fsau wildcard
        if (in_array('*', $this->abilities)) {
            return true;
        }

        return in_array($ability, $this->abilities);
    }

    /**
     * Check if IP is whitelisted
     */
    public function isIpAllowed(string $ip): bool
    {
        if (empty($this->ip_whitelist)) {
            return true; // No whitelist = all IPs allowed
        }

        return in_array($ip, $this->ip_whitelist);
    }

    /**
     * Check if token is expired
     */
    public function isExpired(): bool
    {
        if (!$this->expires_at) {
            return false;
        }

        return $this->expires_at->isPast();
    }

    /**
     * Check if token is valid
     */
    public function isValid(): bool
    {
        return $this->is_active && !$this->isExpired();
    }

    /**
     * Update last used timestamp
     */
    public function markAsUsed(): void
    {
        $this->update(['last_used_at' => now()]);
    }

    /**
     * Get usage statistics for today
     */
    public function getTodayUsage(): int
    {
        return $this->requests()
            ->whereDate('created_at', today())
            ->count();
    }

    /**
     * Get usage statistics for current hour
     */
    public function getHourlyUsage(): int
    {
        return $this->requests()
            ->where('created_at', '>=', now()->startOfHour())
            ->count();
    }

    /**
     * Scope: Active tokens only
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true)
            ->where(function ($q) {
                $q->whereNull('expires_at')
                    ->orWhere('expires_at', '>', now());
            });
    }
}
