<?php

/*
 * This file is part of the AuthStack project.
 *
 * (c) Buckhill Ltd <development@buckhill.co.uk>
 *
 * This source file is subject to the Buckhill license that is bundled
 * with this source code in the file LICENSE.
 */

namespace AuthStack\Driver\LDAP;

use AuthStack\Driver\LDAP\User;
use AuthStack\Driver\Model\SecurityKey;
use AuthStack\Driver\Errors\NoUserObjectError;
use AuthStack\Driver\Collection\TwoFactorKeys;
use AuthStack\Driver\Driver\AuthDriverInterface;

class LDAP extends AbstractLDAP implements AuthDriverInterface
{
    /**
     * @param array $credentials
     *
     * @return bool
     *
     * @throws \AuthStack\Driver\Errors\ConnectionError
     * @throws \AuthStack\Driver\Errors\InsufficientCredentialsError
     */
    public function authenticate(array $credentials)
    {
        $this->check($credentials);

        $username = $this->username($credentials['username']);
        $password = trim($credentials['password']);

        $result = $this->getConnection()->authenticate($username, $password);

        if ($result) {
            $this->retrieveUser($credentials['username']);
        }

        return $result;
    }


    /**
     * @return array
     */
    public static function install()
    {
        return [
            'title'         => 'LDAP',
            'description'   => 'Configurable LDAP driver',
            'class_path'    => 'AuthStack\\Driver\\LDAP\\LDAP'
        ];
    }

    /**
     * @return User
     *
     * @throws NoUserObjectError
     */
    public function getUser()
    {
        if (!$this->user instanceof User) {
            throw new NoUserObjectError('There is no user object available. You must successfully authenticate first.');
        }

        return $this->user;
    }


    /**
     * @param $username
     *
     * @return User
     * @throws NoUserObjectError
     */
    public function getUserByUsername($username)
    {
        $this->retrieveUser($username);

        return $this->getUser();
    }


    /**
     * @param $id
     *
     * @return User
     * @throws NoUserObjectError
     */
    public function getUserByPrimaryKey($id)
    {
        $this->retrieveUser($id);

        return $this->getUser();
    }


    /**
     * @return bool
     */
    public function passwordChangeAllowed()
    {
        return false;
    }


    /**
     * @param array $data
     *
     * @return bool
     */
    public function changePassword(array $data)
    {
        return false;
    }


    /**
     * @param $username
     *
     * @throws NoUserObjectError
     * @throws \AuthStack\Driver\Errors\NoProvisionedUserError
     */
    protected function retrieveUser($username)
    {
        // Retrieve the object which holds user information
        $this->fetchUser($username);

        // Provision to AuthStack's database so we can associate security keys
        // with people from various authsources
        //$this->provision($this->username($username));
        $this->provision($username);

        // Associate the user object with the model that handles provisioned users in AuthStack's database
        $this->getUser()->setProvisionedUser($this->provisioned);

        // AuthStack Id comes from ProvisionedUser model, so we'll set it now
        $this->getUser()->setAuthstackID($this->provisioned->id);

        $this->getUser()->setAuthsourceID($this->getAuthSourceId());

        // Retrieve a list of security (two factor) keys associated with this user's account
        $keys = TwoFactorKeys::fromArray(
            SecurityKey::where("user_id", $this->getUser()->getProvisionedUser()->id)->get()->toArray()
        );

        // Set the key collection for the user
        $this->getUser()->setKeyCollection($keys);
    }
}
