<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Support\Facades\Crypt;

class SharedSocialAccess extends Model
{
    use HasFactory, SoftDeletes;

    protected $table = 'shared_social_access';

    protected $fillable = [
        'connection_id',
        'creator_id',
        'brand_id',
        'campaign_id',
        'allowed_scopes',
        'access_level',
        'scoped_access_token',
        'token_expires_at',
        'granted_at',
        'expires_at',
        'revoked_at',
        'revoked_by',
        'revocation_reason',
        'status',
        'last_used_at',
        'usage_count',
        'creator_consent',
        'consent_given_at',
        'consent_ip',
        'consent_user_agent',
        'creator_notified',
        'brand_notified',
        'expiry_warning_sent',
        'granted_by',
        'audit_trail',
    ];

    protected $casts = [
        'allowed_scopes' => 'array',
        'token_expires_at' => 'datetime',
        'granted_at' => 'datetime',
        'expires_at' => 'datetime',
        'revoked_at' => 'datetime',
        'last_used_at' => 'datetime',
        'consent_given_at' => 'datetime',
        'creator_consent' => 'boolean',
        'creator_notified' => 'boolean',
        'brand_notified' => 'boolean',
        'expiry_warning_sent' => 'boolean',
        'usage_count' => 'integer',
        'audit_trail' => 'array',
    ];

    protected $hidden = [
        'scoped_access_token',
    ];

    /**
     * The attributes that should be encrypted.
     */
    protected $encrypted = [
        'scoped_access_token',
    ];

    /**
     * Boot the model.
     */
    protected static function boot()
    {
        parent::boot();

        // Automatically encrypt sensitive fields on save
        static::saving(function ($model) {
            foreach ($model->encrypted as $field) {
                if ($model->isDirty($field) && !empty($model->$field)) {
                    // Only encrypt if not already encrypted
                    if (!str_starts_with($model->$field, 'eyJpdiI6')) {
                        $model->attributes[$field] = Crypt::encryptString($model->$field);
                    }
                }
            }
        });

        // Auto-update status based on expiry
        static::saving(function ($model) {
            if ($model->expires_at && $model->expires_at->lte(now()) && $model->status === 'active') {
                $model->status = 'expired';
            }
        });

        // Track usage
        static::creating(function ($model) {
            if (!$model->granted_at) {
                $model->granted_at = now();
            }
            if (!$model->granted_by) {
                $model->granted_by = auth()->id();
            }
        });
    }

    /**
     * Get decrypted value for encrypted fields.
     */
    public function getAttribute($key)
    {
        $value = parent::getAttribute($key);

        if (in_array($key, $this->encrypted) && !empty($value)) {
            try {
                return Crypt::decryptString($value);
            } catch (\Exception $e) {
                return null;
            }
        }

        return $value;
    }

    /**
     * Get the connection that this access is for.
     */
    public function connection()
    {
        return $this->belongsTo(CreatorSocialConnection::class, 'connection_id');
    }

    /**
     * Get the creator who owns the connection.
     */
    public function creator()
    {
        return $this->belongsTo(User::class, 'creator_id');
    }

    /**
     * Get the brand that has access.
     */
    public function brand()
    {
        return $this->belongsTo(Brand::class);
    }

    /**
     * Get the campaign this access is for (optional).
     */
    public function campaign()
    {
        return $this->belongsTo(Campaign::class);
    }

    /**
     * Get the user who granted access.
     */
    public function grantedBy()
    {
        return $this->belongsTo(User::class, 'granted_by');
    }

    /**
     * Get the user who revoked access.
     */
    public function revokedBy()
    {
        return $this->belongsTo(User::class, 'revoked_by');
    }

    /**
     * Scope to get only active access.
     */
    public function scopeActive($query)
    {
        return $query->where('status', 'active')
            ->where('expires_at', '>', now())
            ->whereNull('revoked_at');
    }

    /**
     * Scope to get expiring access.
     */
    public function scopeExpiring($query, $days = 7)
    {
        return $query->where('status', 'active')
            ->where('expires_at', '<=', now()->addDays($days))
            ->where('expires_at', '>', now())
            ->whereNull('revoked_at');
    }

    /**
     * Scope to get expired access.
     */
    public function scopeExpired($query)
    {
        return $query->where(function ($q) {
            $q->where('status', 'expired')
              ->orWhere('expires_at', '<=', now());
        });
    }

    /**
     * Check if access is currently valid.
     */
    public function isValid(): bool
    {
        return $this->status === 'active' 
            && $this->expires_at->gt(now())
            && is_null($this->revoked_at);
    }

    /**
     * Check if access is expiring soon.
     */
    public function isExpiringSoon($days = 7): bool
    {
        if (!$this->isValid()) {
            return false;
        }

        return $this->expires_at->lte(now()->addDays($days));
    }

    /**
     * Revoke access.
     */
    public function revoke(string $reason = null, int $revokedBy = null): bool
    {
        $this->update([
            'status' => 'revoked',
            'revoked_at' => now(),
            'revoked_by' => $revokedBy ?? auth()->id(),
            'revocation_reason' => $reason,
        ]);

        $this->addAuditEntry('revoked', [
            'reason' => $reason,
            'revoked_by' => $revokedBy ?? auth()->id(),
        ]);

        return true;
    }

    /**
     * Record usage of this access.
     */
    public function recordUsage(): void
    {
        $this->increment('usage_count');
        $this->update(['last_used_at' => now()]);

        $this->addAuditEntry('used', [
            'usage_count' => $this->usage_count,
        ]);
    }

    /**
     * Add entry to audit trail.
     */
    public function addAuditEntry(string $action, array $data = []): void
    {
        $trail = $this->audit_trail ?? [];
        
        $trail[] = [
            'action' => $action,
            'timestamp' => now()->toIso8601String(),
            'user_id' => auth()->id(),
            'data' => $data,
        ];

        $this->update(['audit_trail' => $trail]);
    }

    /**
     * Get time remaining until expiry.
     */
    public function getTimeRemainingAttribute(): string
    {
        if (!$this->expires_at) {
            return 'No expiry';
        }

        if ($this->expires_at->isPast()) {
            return 'Expired';
        }

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

    /**
     * Get status badge color.
     */
    public function getStatusColorAttribute(): string
    {
        return match($this->status) {
            'active' => 'success',
            'expired' => 'warning',
            'revoked' => 'danger',
            default => 'secondary',
        };
    }

    /**
     * Get access level display name.
     */
    public function getAccessLevelDisplayAttribute(): string
    {
        return match($this->access_level) {
            'read_only' => 'Read Only',
            'read_write' => 'Read & Write',
            'full' => 'Full Access',
            default => ucfirst($this->access_level),
        };
    }

    /**
     * Check if a specific scope is allowed.
     */
    public function hasScope(string $scope): bool
    {
        return in_array($scope, $this->allowed_scopes ?? []);
    }

    /**
     * Get formatted allowed scopes.
     */
    public function getFormattedScopesAttribute(): array
    {
        $scopeLabels = [
            'read_profile' => 'View Profile',
            'read_posts' => 'View Posts',
            'read_analytics' => 'View Analytics',
            'publish_content' => 'Publish Content',
            'manage_comments' => 'Manage Comments',
            'manage_ads' => 'Manage Ads',
        ];

        return collect($this->allowed_scopes ?? [])
            ->map(fn($scope) => $scopeLabels[$scope] ?? ucfirst(str_replace('_', ' ', $scope)))
            ->toArray();
    }
}