<?php

namespace AuthStack\Driver\AUDGeneric;

use Exception;
use Illuminate\Http\JsonResponse;
use AuthStack\Driver\Driver\AuthDriverInterface;
use AuthStack\Driver\AUDGeneric\App\REST\AUDModel;
use AuthStack\Driver\Traits\TraitTemplateVariables;
use Illuminate\Contracts\Filesystem\FileNotFoundException;

class Driver extends AbstractDriver implements AuthDriverInterface
{
    use TraitTemplateVariables;

    protected $authsource_id;

    public function __construct()
    {
        $this->authsource_id = (new AUDModel())->getAuthSourceId();
    }

    /**
     * Reads driver.json found in the same directory and returns it as an array
     * You can re-implement this method to return an array which conforms to JSON schema
     * JSON schema information: http://json-schema.org/
     *
     * @return mixed
     * @throws FileNotFoundException
     */
    public static function install()
    {
        return [];
    }

    public function connect()
    {
        // This method handles connecting to authentication source.
        // For MySQL connections, you'd create a PDO instance in this method
        // For LDAP connections, you'd use ldap_connect in this method
        // For RESTful connections, you'd create Guzzle instances here or manually set curl handles
    }

    /**
     * @param array $data
     * @return array|bool
     * @throws Exception
     */
    public function authenticate(array $data)
    {
        $result = (new AUDModel)->getAuthentication($data);

        if (!empty($result) && (!isset($data['test']) || !$data['test']))
        {
            $this->user = User::initialize(collect($result), 'aud');

            $this->provision($data['username']);

            $this
                ->provisioned
                ->updateUserConfig(['attributes' => $result])
                ->save();

            $this->user->setAuthstackID($this->getProvisionedUser()->getAttribute('id'));
            $this->user->setUsername($data['username']);

            $this->getUser()->setProvisionedUser($this->provisioned);
        }

        return !empty($result);
    }

    public function passwordChangeAllowed()
    {
        // Indicates whether this driver allows password change through Authstack UI or not
        // Expects a boolean return. If false is returned, AuthStack won't render password change menu

        return false;
    }


    public function changePassword(array $data)
    {
        // This method handles password change, if it's allowed.
        // Password is changed through AuthStack UI, when user is authenticated via this driver
        // If you don't want to implement password change, simply return true from this method

        return true;
    }

    public function getUser()
    {
        // This method must return an instance of User, the class created in the same directory / namespace as this one
        // When user is authenticated, User object must be available since it deals with attributes and user provisioning

        return $this->user;
    }

    /**
     * @param $id
     * @return User|\AuthStack\Driver\Model\User
     * @throws Exception
     */
    public function getUserByPrimaryKey($id)
    {
        try
        {
            $model = new AUDModel();
            $auth = $model->getUserByPrimaryKey($id);
            $data = (array)$auth->getData()->account;

            if (!empty($data))
            {
                $this->user = User::initialize(collect($data), 'aud');

                $this->provision($data['username_readable']);

                $this
                    ->provisioned
                    ->updateUserConfig(['attributes' => $data])
                    ->save();

                $this->user->setAuthstackID($this->getProvisionedUser()->getAttribute('id'));
                $this->user->setUsername($data['username']);

                $this->getUser()->setProvisionedUser($this->provisioned);
            }

            return $this->user;

        } catch (Exception $e) {
            \Log::error('Silent SSO:', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine()
            ]);
        }
    }

    public function getUserByUsername($username)
    {
        // Retrieves an insatnce of User using username as attribute
        // This is driver logic dependent, but should be implemented. Username supplied as the parameter is the username
        // used during authentication
        // This method is used for SAML 2.0 auto-authentication

        try
        {
            $model = new AUDModel();
            $auth = $model->getUserByUsername($username);
            $data = (array)$auth->getData()->account;

            if (!empty($data))
            {
                $this->user = User::initialize(collect($data), 'aud');

                $this->provision($data['username_readable']);

                $this
                    ->provisioned
                    ->updateUserConfig(['attributes' => $data])
                    ->save();

                $this->user->setAuthstackID($this->getProvisionedUser()->getAttribute('id'));
                $this->user->setUsername($data['username']);

                $this->getUser()->setProvisionedUser($this->provisioned);
            }

            return $this->user;

        } catch (Exception $e) {
            \Log::error('Silent SSO:', [
                'message' => $e->getMessage(),
                'file' => $e->getFile(),
                'line' => $e->getLine()
            ]);
        }
    }
}
