<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Carbon\Carbon;

class UserSession extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'session_start',
        'session_end',
        'ip_address',
        'user_agent',
        'duration_seconds',
        'pages_visited',
        'actions_count',
    ];

    protected $casts = [
        'session_start' => 'datetime',
        'session_end' => 'datetime',
        'duration_seconds' => 'integer',
        'pages_visited' => 'integer',
        'actions_count' => 'integer',
    ];

    /**
     * Get the user that owns the session
     */
    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    /**
     * Scope for active sessions
     */
    public function scopeActive($query)
    {
        return $query->whereNull('session_end');
    }

    /**
     * Scope for completed sessions
     */
    public function scopeCompleted($query)
    {
        return $query->whereNotNull('session_end');
    }

    /**
     * Scope for sessions in date range
     */
    public function scopeInDateRange($query, $startDate, $endDate = null)
    {
        $endDate = $endDate ?: now();
        return $query->whereBetween('session_start', [$startDate, $endDate]);
    }

    /**
     * Scope for sessions by user
     */
    public function scopeForUser($query, $userId)
    {
        return $query->where('user_id', $userId);
    }

    /**
     * End the session
     */
    public function endSession(): void
    {
        if ($this->session_end) {
            return; // Already ended
        }

        $this->update([
            'session_end' => now(),
            'duration_seconds' => $this->calculateDuration(),
        ]);
    }

    /**
     * Calculate session duration in seconds
     */
    public function calculateDuration(): int
    {
        if (!$this->session_end) {
            return now()->diffInSeconds($this->session_start);
        }

        return $this->session_end->diffInSeconds($this->session_start);
    }

    /**
     * Get formatted duration
     */
    public function getFormattedDurationAttribute(): string
    {
        $duration = $this->calculateDuration();
        
        if ($duration < 60) {
            return $duration . ' seconds';
        } elseif ($duration < 3600) {
            return round($duration / 60, 1) . ' minutes';
        } else {
            return round($duration / 3600, 1) . ' hours';
        }
    }

    /**
     * Check if session is active
     */
    public function isActive(): bool
    {
        return $this->session_end === null;
    }

    /**
     * Check if session is expired (inactive for more than timeout)
     */
    public function isExpired(int $timeoutMinutes = 30): bool
    {
        if ($this->session_end) {
            return false; // Already ended
        }

        return $this->updated_at->addMinutes($timeoutMinutes)->isPast();
    }

    /**
     * Get session status
     */
    public function getStatusAttribute(): string
    {
        if ($this->session_end) {
            return 'completed';
        }
        
        if ($this->isExpired()) {
            return 'expired';
        }
        
        return 'active';
    }

    /**
     * Increment pages visited
     */
    public function incrementPagesVisited(): void
    {
        $this->increment('pages_visited');
        $this->touch();
    }

    /**
     * Increment actions count
     */
    public function incrementActionsCount(): void
    {
        $this->increment('actions_count');
        $this->touch();
    }

    /**
     * Get average session duration for a user
     */
    public static function getAverageSessionDuration(int $userId, int $days = 30): float
    {
        return static::forUser($userId)
            ->completed()
            ->where('session_start', '>=', now()->subDays($days))
            ->avg('duration_seconds') ?? 0;
    }

    /**
     * Get total session count for a user
     */
    public static function getTotalSessions(int $userId, int $days = 30): int
    {
        return static::forUser($userId)
            ->where('session_start', '>=', now()->subDays($days))
            ->count();
    }

    /**
     * Get active sessions count
     */
    public static function getActiveSessions(): int
    {
        return static::active()->count();
    }

    /**
     * Close expired sessions
     */
    public static function closeExpiredSessions(int $timeoutMinutes = 30): int
    {
        $cutoff = now()->subMinutes($timeoutMinutes);
        
        $expiredSessions = static::active()
            ->where('updated_at', '<', $cutoff)
            ->get();

        foreach ($expiredSessions as $session) {
            $session->update([
                'session_end' => $session->updated_at->addMinutes($timeoutMinutes),
                'duration_seconds' => $session->updated_at->addMinutes($timeoutMinutes)
                    ->diffInSeconds($session->session_start),
            ]);
        }

        return $expiredSessions->count();
    }

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

        // Set default values when creating
        static::creating(function ($session) {
            if (!$session->pages_visited) {
                $session->pages_visited = 0;
            }
            
            if (!$session->actions_count) {
                $session->actions_count = 0;
            }
        });
    }
}