<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Casts\Attribute;

/**
 * GoogleMeetConfiguration Model
 * 
 * Stores OAuth2 credentials for Google Meet API integration.
 * All sensitive fields are encrypted at rest using Laravel's encrypted casting.
 * 
 * @property int $id
 * @property string $client_id Google OAuth2 Client ID (encrypted)
 * @property string $client_secret Google OAuth2 Client Secret (encrypted)
 * @property string $redirect_uri OAuth2 callback URL
 * @property string|null $access_token Access token (encrypted)
 * @property string|null $refresh_token Refresh token (encrypted)
 * @property \Illuminate\Support\Carbon|null $token_expires_at Token expiration timestamp
 * @property bool $is_active Whether this configuration is active
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * 
 * @see https://developers.google.com/identity/protocols/oauth2
 */
class GoogleMeetConfiguration extends Model
{
    use HasFactory;

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'client_id',
        'client_secret',
        'redirect_uri',
        'access_token',
        'refresh_token',
        'token_expires_at',
        'is_active',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'client_id' => 'encrypted',
        'client_secret' => 'encrypted',
        'access_token' => 'encrypted',
        'refresh_token' => 'encrypted',
        'token_expires_at' => 'datetime',
        'is_active' => 'boolean',
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'client_secret',
        'access_token',
        'refresh_token',
    ];

    /*
    |--------------------------------------------------------------------------
    | Token Management Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Check if OAuth2 tokens are present.
     *
     * @return bool
     */
    public function hasTokens(): bool
    {
        return !empty($this->access_token) && !empty($this->refresh_token);
    }

    /**
     * Check if the access token has expired.
     *
     * @return bool
     */
    public function isTokenExpired(): bool
    {
        if (!$this->token_expires_at) {
            return true;
        }

        // Consider token expired 5 minutes before actual expiration
        return $this->token_expires_at->subMinutes(5)->isPast();
    }

    /**
     * Check if the access token is valid and not expired.
     *
     * @return bool
     */
    public function hasValidToken(): bool
    {
        return $this->hasTokens() && !$this->isTokenExpired();
    }

    /**
     * Get the number of minutes until token expires.
     *
     * @return int|null
     */
    public function getMinutesUntilExpiration(): ?int
    {
        if (!$this->token_expires_at) {
            return null;
        }

        $diff = now()->diffInMinutes($this->token_expires_at, false);
        return $diff > 0 ? $diff : 0;
    }

    /**
     * Check if configuration is fully set up and authenticated.
     *
     * @return bool
     */
    public function isFullyConfigured(): bool
    {
        return $this->is_active
            && !empty($this->client_id)
            && !empty($this->client_secret)
            && !empty($this->redirect_uri)
            && $this->hasValidToken();
    }

    /*
    |--------------------------------------------------------------------------
    | Scopes
    |--------------------------------------------------------------------------
    */

    /**
     * Scope to get only active configurations.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeActive($query)
    {
        return $query->where('is_active', true);
    }

    /**
     * Scope to get only configured (having credentials) configurations.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeConfigured($query)
    {
        return $query->whereNotNull('client_id')
            ->whereNotNull('client_secret')
            ->whereNotNull('redirect_uri');
    }

    /**
     * Scope to get only authenticated (having valid tokens) configurations.
     *
     * @param \Illuminate\Database\Eloquent\Builder $query
     * @return \Illuminate\Database\Eloquent\Builder
     */
    public function scopeAuthenticated($query)
    {
        return $query->whereNotNull('access_token')
            ->whereNotNull('refresh_token')
            ->where('token_expires_at', '>', now());
    }

    /*
    |--------------------------------------------------------------------------
    | Static Helper Methods
    |--------------------------------------------------------------------------
    */

    /**
     * Get the active configuration.
     *
     * @return self|null
     */
    public static function getActive(): ?self
    {
        return static::active()->first();
    }

    /**
     * Check if Google Meet is configured.
     *
     * @return bool
     */
    public static function isConfigured(): bool
    {
        return static::active()->exists();
    }

    /**
     * Check if Google Meet is authenticated.
     *
     * @return bool
     */
    public static function isAuthenticated(): bool
    {
        $config = static::getActive();
        return $config && $config->hasValidToken();
    }
}
