<?php

namespace Tests\Property;

use Tests\PropertyTestCase;

/**
 * Session Management Property Tests
 * Tests universal properties of session management
 */
class SessionPropertyTest extends PropertyTestCase {
    
    /**
     * Feature: birthday-reminder-pwa, Property 2: Sessions persist until explicit logout
     * 
     * For any authenticated session, the session should remain valid indefinitely
     * until logout is explicitly triggered.
     * 
     * Validates: Requirements 1.2
     * 
     * @test
     */
    public function testSessionsPersistUntilExplicitLogout() {
        $this->runPropertyTest(function($iteration) {
            // Reset database for clean state
            resetTestDatabase();
            
            // Create and authenticate user
            $username = 'user_' . randomString(8);
            $password = 'pass_' . randomString(10);
            $email = randomEmail();
            
            $userModel = new \User();
            $userId = $userModel->create([
                'username' => $username,
                'password' => $password,
                'email' => $email,
                'is_active' => 1
            ]);
            
            // Authenticate and create session
            $authenticatedUser = $userModel->authenticate($username, $password);
            $this->assertNotFalse($authenticatedUser);
            
            $sessionId = $authenticatedUser->createSession();
            $this->assertNotEmpty($sessionId);
            
            // Verify session exists in database
            $db = \Database::getInstance();
            $session = $db->fetchOne("SELECT * FROM sessions WHERE id = ?", [$sessionId]);
            $this->assertNotFalse($session, "Session not found in database on iteration $iteration");
            
            // Verify session is valid
            $isValid = $userModel->validateSession($userId);
            $this->assertTrue($isValid, "Session should be valid on iteration $iteration");
            
            // Simulate time passing - session should still be valid
            // (In real scenario, this would test across multiple requests)
            $isStillValid = $userModel->validateSession($userId);
            $this->assertTrue($isStillValid, "Session should persist on iteration $iteration");
            
            // Verify session variables are still set
            $this->assertEquals($userId, $_SESSION['user_id'], "Session user_id should persist on iteration $iteration");
            $this->assertEquals($username, $_SESSION['username'], "Session username should persist on iteration $iteration");
        });
    }
    
    /**
     * Feature: birthday-reminder-pwa, Property 4: Logout terminates sessions
     * 
     * For any active session, when logout is triggered, the session should be
     * terminated and no longer grant access.
     * 
     * Validates: Requirements 1.5
     * 
     * @test
     */
    public function testLogoutTerminatesSessions() {
        $this->runPropertyTest(function($iteration) {
            // Reset database for clean state
            resetTestDatabase();
            
            // Create and authenticate user
            $username = 'user_' . randomString(8);
            $password = 'pass_' . randomString(10);
            $email = randomEmail();
            
            $userModel = new \User();
            $userId = $userModel->create([
                'username' => $username,
                'password' => $password,
                'email' => $email,
                'is_active' => 1
            ]);
            
            // Authenticate and create session
            $authenticatedUser = $userModel->authenticate($username, $password);
            $sessionId = $authenticatedUser->createSession();
            
            // Verify session exists before logout
            $this->assertTrue(isset($_SESSION['user_id']), "Session should exist before logout on iteration $iteration");
            
            $db = \Database::getInstance();
            $sessionBefore = $db->fetchOne("SELECT * FROM sessions WHERE id = ?", [$sessionId]);
            $this->assertNotFalse($sessionBefore, "Session should exist in database before logout on iteration $iteration");
            
            // Perform logout
            $logoutResult = $authenticatedUser->destroySession();
            $this->assertTrue($logoutResult, "Logout should succeed on iteration $iteration");
            
            // Verify session is destroyed
            $this->assertFalse(isset($_SESSION['user_id']), "Session user_id should be cleared after logout on iteration $iteration");
            $this->assertEmpty($_SESSION, "Session should be empty after logout on iteration $iteration");
            
            // Verify session is removed from database
            $sessionAfter = $db->fetchOne("SELECT * FROM sessions WHERE id = ?", [$sessionId]);
            $this->assertFalse($sessionAfter, "Session should be removed from database after logout on iteration $iteration");
            
            // Verify session validation fails after logout
            // Need to restart session for validation check
            if (session_status() === PHP_SESSION_NONE) {
                session_start();
            }
            $isValid = $userModel->validateSession($userId);
            $this->assertFalse($isValid, "Session should not be valid after logout on iteration $iteration");
        });
    }
    
    /**
     * Test that inactive users cannot have valid sessions
     * 
     * @test
     */
    public function testInactiveUsersCannotHaveValidSessions() {
        $this->runPropertyTest(function($iteration) {
            // Reset database for clean state
            resetTestDatabase();
            
            // Create user
            $username = 'user_' . randomString(8);
            $password = 'pass_' . randomString(10);
            $email = randomEmail();
            
            $userModel = new \User();
            $userId = $userModel->create([
                'username' => $username,
                'password' => $password,
                'email' => $email,
                'is_active' => 1
            ]);
            
            // Authenticate and create session
            $authenticatedUser = $userModel->authenticate($username, $password);
            $authenticatedUser->createSession();
            
            // Verify session is valid
            $this->assertTrue($userModel->validateSession($userId));
            
            // Deactivate user
            $userModel->update($userId, ['is_active' => 0]);
            
            // Verify session is no longer valid
            $isValid = $userModel->validateSession($userId);
            $this->assertFalse($isValid, "Inactive user should not have valid session on iteration $iteration");
        }, 50); // Run 50 iterations for this test
    }
}
