<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Carbon\Carbon;

/**
 * OAuth Token Model
 * 
 * Unified model for storing OAuth tokens from various providers
 */
class OAuthToken extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'oauth_tokens';

    protected $fillable = [
        'provider',
        'provider_type',
        'scope',
        'user_id',
        'tenant_id',
        'access_token',
        'refresh_token',
        'expires_at',
        'scopes',
        'provider_data',
        'token_type',
        'status',
        'connected_at',
        'last_used_at'
    ];

    protected $casts = [
        'expires_at' => 'datetime',
        'connected_at' => 'datetime',
        'last_used_at' => 'datetime',
        'scopes' => 'array',
        'provider_data' => 'array'
    ];

    protected $hidden = [
        'access_token',
        'refresh_token'
    ];

    /**
     * Relationships
     */
    public function user()
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Scopes
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active');
    }

    public function scopeForProvider($query, $provider)
    {
        return $query->where('provider', $provider);
    }

    public function scopeSystemWide($query)
    {
        return $query->where('scope', 'system');
    }

    public function scopeForUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }

    public function scopeForTenant($query, $tenantId)
    {
        return $query->where('tenant_id', $tenantId);
    }

    public function scopeExpiringSoon($query, $hours = 24)
    {
        return $query->where('expires_at', '<=', Carbon::now()->addHours($hours))
                    ->whereNotNull('expires_at');
    }

    /**
     * Accessors & Mutators
     */
    public function getIsExpiredAttribute()
    {
        if (!$this->expires_at) {
            return false;
        }

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

    public function getIsExpiringSoonAttribute()
    {
        if (!$this->expires_at) {
            return false;
        }

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

    public function getProviderDisplayNameAttribute()
    {
        return match($this->provider) {
            'xero' => 'Xero',
            'twilio' => 'Twilio',
            'google' => 'Google',
            'microsoft' => 'Microsoft',
            'github' => 'GitHub',
            'stripe' => 'Stripe',
            'paypal' => 'PayPal',
            default => ucfirst($this->provider)
        };
    }

    public function getScopeDisplayNameAttribute()
    {
        return match($this->scope) {
            'system' => 'System-wide',
            'user' => 'User-specific',
            'tenant' => 'Organization-specific',
            default => ucfirst($this->scope)
        };
    }

    /**
     * Helper methods
     */
    public function isValid(): bool
    {
        return $this->status === 'active' && !$this->is_expired;
    }

    public function markAsUsed(): void
    {
        $this->update(['last_used_at' => Carbon::now()]);
    }

    public function markAsExpired(): void
    {
        $this->update(['status' => 'expired']);
    }

    public function markAsRevoked(): void
    {
        $this->update(['status' => 'revoked']);
    }

    /**
     * Get provider-specific data
     */
    public function getProviderData($key = null, $default = null)
    {
        if ($key === null) {
            return $this->provider_data;
        }

        return data_get($this->provider_data, $key, $default);
    }

    /**
     * Set provider-specific data
     */
    public function setProviderData($key, $value = null): void
    {
        $data = $this->provider_data ?? [];

        if (is_array($key)) {
            $data = array_merge($data, $key);
        } else {
            $data[$key] = $value;
        }

        $this->update(['provider_data' => $data]);
    }

    /**
     * Check if token has specific scope
     */
    public function hasScope(string $scope): bool
    {
        if (!$this->scopes) {
            return false;
        }

        return in_array($scope, $this->scopes);
    }

    /**
     * Get time until expiry
     */
    public function getTimeUntilExpiryAttribute(): ?string
    {
        if (!$this->expires_at) {
            return null;
        }

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