<?php

namespace Velis\Test\Session;

use PHPUnit\Framework\TestCase;
use Redis;
use Velis\App;
use Velis\Arrays;
use Velis\Db\Db;
use Velis\Session\RedisSession;
use Velis\Session\SessionFactoryInterface;
use Velis\User;

/**
 * @author Jan Małysiak <jan.malysiak@velis.pl>
 */
class RedisSessionFunctionalTest extends TestCase
{
    /**
     * @var RedisSession
     */
    private $session;

    /**
     * @var string
     */
    private $prefix;

    /**
     * @var Redis
     */
    private $redis;

    protected function setUp(): void
    {
        $config = Arrays::toArray(App::$config->session);
        $this->prefix = uniqid();
        $config['prefix'] = $this->prefix;

        /** @var SessionFactoryInterface $factory */
        $factory = App::$di->get('sessionFactory');
        $this->session = $factory->createRedisSession($config);
        $this->session->start();

        $this->redis = new Redis();
        $this->redis->connect($config['host'], $config['port'] ?? 6379);
    }

    /**
     * @param User $user
     *
     * @dataProvider provideUser
     * @runInSeparateProcess
     */
    public function testRemoveSessions(User $user)
    {
        $this->prepareUserSession($user);

        $keys = $this->redis->keys(sprintf('_PHCR%ssessions%s', $this->prefix, $user->id()));
        $this->assertNotEmpty($keys);

        $sessionListKey = reset($keys);
        $sessionList = unserialize($this->redis->get($sessionListKey));
        $this->assertNotEmpty($sessionList);

        $sessionId = reset($sessionList);
        $sessionExists = $this->redis->exists(sprintf('_PHCR%s%s', $this->prefix, $sessionId));
        $this->assertEquals(1, $sessionExists);

        $this->session->removeSessions($user);

        $sessionExists = $this->redis->exists(sprintf('_PHCR%s%s', $this->prefix, $sessionId));
        $this->assertEquals(0, $sessionExists);

        $sessionList = unserialize($this->redis->get($sessionListKey));
        $this->assertEmpty($sessionList);

        $keys = $this->redis->keys(sprintf('_PHCR%ssessions%s', $this->prefix, $user->id()));
        $this->assertEmpty($keys);
    }

    public function provideUser()
    {
        /** @var Db $db */
        $db = App::$di['db'];
        $row = $db->getRow("SELECT * FROM acl.user_tab LIMIT 1");
        $user = new User($row);

        return [
            [$user],
        ];
    }

    private function prepareUserSession(User $user)
    {
        $prefix = '_PHCR' . $this->prefix;
        $sessionListKey = $prefix . RedisSession::SESSION_STORE_KEY . $user->id();

        $sessionId = uniqid();
        $sessionList = [$sessionId => $sessionId];
        $this->redis->set($sessionListKey, serialize($sessionList));

        $sessionId = reset($sessionList);
        $sessionKey = $prefix . $sessionId;
        $this->redis->set($sessionKey, md5(microtime()));
    }
}
