<?php

namespace AuthStack\Driver\LDAP\tests\units;

use Buckhill\LDAP\EntryCollection;
use mageekguy\atoum;
use function Buckhill\config;
use AuthStack\Driver\LDAP\User;
use AuthStack\Driver\Errors\ConnectionError;
use AuthStack\Driver\LDAP\LDAP as LDAPDriver;
use AuthStack\Driver\Errors\NoAuthSourceError;
use AuthStack\Driver\Errors\NoUserObjectError;
use AuthStack\Driver\Errors\InsufficientCredentialsError;

class LDAP extends atoum
{

    public function testConnectionOK()
    {
        $this
            ->given(config()->set('LDAPTest', $this->config()))
            ->and($ldap = LDAPDriver::initialize('LDAPTest', 2))
            ->then
            ->object($ldap)->isInstanceOf(LDAPDriver::class)
            ->boolean($ldap->connect())->isTrue()
            ->integer($ldap->getAuthSourceId())->isEqualTo(2)
        ;
    }

    public function testAuth()
    {
        $this
            ->given(config()->set('LDAPTest', $this->config()))
            ->and($ldap = LDAPDriver::initialize('LDAPTest', 2))
            ->and($ldap->setTemplateVariables(['EntityId' => 'APP_A_PROD', 'uid' => 'user1']))
            ->and($ldap->connect())
            ->then
                ->object($ldap)->isInstanceOf(LDAPDriver::class)
                ->boolean($ldap->authenticate(['username' => 'user1', 'password' => 'password']))->isTrue()
                ->object($ldap->getUser())->isInstanceOf(User::class)
                ->string($ldap->lastError())->isEmpty()
                ->boolean($ldap->passwordChangeAllowed())->isFalse()
                ->boolean($ldap->changePassword([]))->isFalse()
                ->object($collection = $ldap->getUser()->getAttributeCollection())->isInstanceOf(EntryCollection::class)
                ->array($roles = $collection->get('roles')->getValue())->hasSize(2)
            ;
    }

    public function testInvalidConfigurationKillsConnecting()
    {
        $this
            ->given(config()->set('LDAPBadTest', $this->getBadConfig()))
            ->and($ldap = LDAPDriver::initialize('LDAPBadTest', 2))
            ->then
            ->exception(function () use ($ldap) {
                $result = $ldap->connect();
            })
            ->isInstanceOf(ConnectionError::class)
        ;
    }

    public function testNoConnection()
    {
        $this
            ->given(config()->set('LDAPTest', $this->config()))
            ->and($ldap = LDAPDriver::initialize('LDAPTest', 2))
            ->then
            ->exception(function () use ($ldap) {
                $conn = $ldap->getConnection();
            })
            ->isInstanceOf(ConnectionError::class)
        ;
    }

    public function testAuthenticationFails()
    {
        $this
            ->given(config()->set('LDAPTest', $this->config()))
            ->and($ldap = LDAPDriver::initialize('LDAPTest', 2))
            ->then
            ->exception(function () use ($ldap) {
                $ldap->authenticate([]);
            })
            ->isInstanceOf(InsufficientCredentialsError::class)

            ->exception(function () use ($ldap) {
                $ldap->authenticate(['username' => 'test']);
            })
            ->isInstanceOf(InsufficientCredentialsError::class)

            ->exception(function () use ($ldap) {
                $ldap->authenticate(['password' => 'test']);
            })
            ->isInstanceOf(InsufficientCredentialsError::class)

            ->exception(function () use ($ldap) {
                $user = $ldap->getUser();
            })
            ->isInstanceOf(NoUserObjectError::class)

            ->exception(function () use ($ldap) {

                $ldap->setAuthSourceId(null);
                $authsource_id = $ldap->getAuthSourceId();
            })
            ->isInstanceOf(NoAuthSourceError::class)

        ;
    }


    protected function config()
    {
        return [

            'filters' => [
                [
                    'title'     => 'test filter',
                    'filter'    => '(&(ou={{ EntityId }})(member=uid={{ uid }},ou=users,dc=fmsapps,dc=com))',
                    'base_dn'   => 'ou=groups,dc=fmsapps,dc=com'
                ]
            ],

            'user_auth' => [
                'dc'    => 'dc=fmsapps,dc=com',
                'ou'    => 'ou=users',
                'uid'   => 'uid'
            ],

            'attributes' => [
                [
                    'name'          => 'cn',
                    'source_id'     => 1,
                    'renamed'       => 'cn',
                ],

                [
                    'name'          => 'sn',
                    'source_id'     => 1,
                    'renamed'       => 'sn',
                ],

                [
                    'name'          => 'customerid',
                    'source_id'     => 1,
                    'renamed'       => 'customerid',
                ],

                [
                    'name'          => 'customertypeid',
                    'source_id'     => 1,
                    'renamed'       => 'customertypeid',
                ],

                [
                    'name'          => 'mail',
                    'source_id'     => 1,
                    'renamed'       => 'mail',
                ],

                [
                    'name'          => 'mercuryuserid',
                    'source_id'     => 1,
                    'renamed'       => 'mercuryuserid',
                ],

                [
                    'name'          => 'uid',
                    'source_id'     => 1,
                    'renamed'       => 'uid',
                ],

                [
                    'name'          => 'cn',
                    'source_id'     => 2,
                    'renamed'       => 'roles',
                ],
            ],

            'connection' => [
                'TLS'   => false,
                'host'  => '10.0.0.119',
                'port'  => '389',
                'options' => [
                    [
                        'name' => LDAP_OPT_PROTOCOL_VERSION,
                        'value' => 3
                    ]
                ],
                'username' => 'cn=admin,dc=fmsapps,dc=com',
                'password' => 'secret'
            ]

        ];
    }

    protected function getBadConfig()
    {
        return [
            'dc' => 'dc=buckhill,dc=co,dc=uk',
            'ou' => 'ou=users',
            'uid' => 'uid',
            'attributes' => [
                'memberof', 'cn', 'dn', 'mail', 'uid', 'givenname', 'sn',
                'telephonenumber', 'postaladdress', 'o', 'l', 'postalcode', 'st',
            ],
            'connection' => [
                'host' => 'this is just a bad string',
                'port' => 1234,
                'base_dn' => 'dc=buckhill,dc=co,dc=uk',
                'TLS' => false,
                'options' => [
                    [
                        'name' => 'bad',
                        'value' => 'options',
                    ],
                ],
            ],
        ];
    }
}