<?php

namespace Velis\Test\Bpm;

use Exception;
use PHPUnit\Framework\TestCase;
use Psr\SimpleCache\InvalidArgumentException;
use Velis\App\User\Authentication;
use Velis\Bpm\User;
use Velis\Model\DataObject\NoColumnsException;

/**
 * @author Jan Małysiak <jan.malysiak@velistech.com>
 */
class UserTest extends TestCase
{
    /**
     * @param string $rawPassword
     * @param string $login
     * @return void
     * @throws NoColumnsException
     *
     * @dataProvider provideTestDataForGetPasswordHashMethod
     */
    public function testGetPasswordHash(string $rawPassword, string $login)
    {
        $hash = User::getPasswordHash($rawPassword, $login);

        $this->assertTrue(password_verify($rawPassword, $hash));
    }

    /**
     * @return array
     */
    public function provideTestDataForGetPasswordHashMethod(): array
    {
        $rawPassword = md5(uniqid());
        $login = 'user1';

        return [
            [$rawPassword, $login],
        ];
    }

    /**
     * @param User $user
     * @param string $rawPassword
     * @param bool $expectedResult
     * @return void
     * @throws Exception
     *
     * @dataProvider provideTestDataForValidatePasswordMethod
     */
    public function testValidatePassword(User $user, string $rawPassword, bool $expectedResult)
    {
        $actualResult = $user->validatePassword($rawPassword);

        $this->assertEquals($expectedResult, $actualResult);
    }

    /**
     * @return array
     * @throws NoColumnsException
     */
    public function provideTestDataForValidatePasswordMethod(): array
    {
        $login = 'user1';
        $rawPassword = md5(uniqid());

        $md5 = md5($login . '|' . $rawPassword);
        $md5User = new User([
            'login' => $login,
            'hash_algorithm' => Authentication::HASH_MD5,
            'password' => $md5,
        ]);

        $bcryptUser = new User([
            'login' => $login,
            'hash_algorithm' => Authentication::HASH_BCRYPT,
            'password' => password_hash($rawPassword, PASSWORD_BCRYPT),
        ]);

        return [
            'md5' => [$md5User, $rawPassword, true],
            'md5 invalid' => [$md5User, 'invalid', false],
            'bcrypt' => [$bcryptUser, $rawPassword, true],
            'bcrypt invalid' => [$bcryptUser, 'invalid', false],
        ];
    }

    /**
     * @param User $user
     * @return void
     * @throws InvalidArgumentException
     *
     * @dataProvider provideSubstituteUsers
     */
    public function testGetSubstitutedUsers(User $user): void
    {
        $substitutedUsers = $user->getSubstitutedUsers();

        self::assertIsArray($substitutedUsers);

        foreach ($substitutedUsers as $substitutedUser) {
            self::assertInstanceOf(User::class, $substitutedUser);
        }
    }

    /**
     * @return array[]
     * @throws NoColumnsException
     */
    public function provideSubstituteUsers(): array
    {
        return [
            [new User(['substitute_for' => '1,2,3'])],
            [new User(['substitute_for' => [1, 2, 3]])],
            [new User()],
        ];
    }

    /**
     * @param User $user
     * @return void
     *
     * @dataProvider provideSubstituteUsers
     */
    public function testGetSubstitutedUserIds(User $user): void
    {
        $substitutedUserIds = $user->getSubstitutedUserIds();

        self::assertIsArray($substitutedUserIds);

        foreach ($substitutedUserIds as $substitutedUserId) {
            self::assertIsInt($substitutedUserId);
        }
    }
}