"use strict";
/*
 * @adonisjs/auth
 *
 * (c) Harminder Virk <virk@adonisjs.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.LucidProvider = void 0;
const hooks_1 = require("@poppinss/hooks");
const utils_1 = require("@poppinss/utils");
const User_1 = require("./User");
/**
 * Lucid provider uses Lucid models to lookup a users
 */
class LucidProvider {
    constructor(application, config) {
        this.application = application;
        this.config = config;
        /**
         * Hooks reference
         */
        this.hooks = new hooks_1.Hooks();
    }
    /**
     * The models options for constructing a query
     */
    getModelOptions() {
        if (typeof this.connection === 'string') {
            return { connection: this.connection };
        }
        if (this.connection) {
            return { client: this.connection };
        }
        return this.config.connection ? { connection: this.config.connection } : {};
    }
    /**
     * Returns the auth model
     */
    async getModel() {
        const model = await this.config.model();
        return (0, utils_1.esmResolver)(model);
    }
    /**
     * Returns query instance for the user model
     */
    async getModelQuery(model) {
        model = model || (await this.getModel());
        return {
            query: model.query(this.getModelOptions()),
        };
    }
    /**
     * Executes the query to find the user, calls the registered hooks
     * and wraps the result inside [[ProviderUserContract]]
     */
    async findUser(query) {
        await this.hooks.exec('before', 'findUser', query);
        const user = await query.first();
        if (user) {
            await this.hooks.exec('after', 'findUser', user);
        }
        return this.getUserFor(user);
    }
    /**
     * Returns an instance of the [[ProviderUser]] by wrapping lucid model
     * inside it
     */
    async getUserFor(user) {
        const UserBuilder = this.config.user ? (0, utils_1.esmResolver)(await this.config.user()) : User_1.LucidUser;
        return this.application.container.makeAsync(UserBuilder, [user, this.config]);
    }
    /**
     * Define custom connection
     */
    setConnection(connection) {
        this.connection = connection;
        return this;
    }
    /**
     * Define before hooks. Check interface for exact type information
     */
    before(event, callback) {
        this.hooks.add('before', event, callback);
        return this;
    }
    /**
     * Define after hooks. Check interface for exact type information
     */
    after(event, callback) {
        this.hooks.add('after', event, callback);
        return this;
    }
    /**
     * Returns a user instance using the primary key value
     */
    async findById(id) {
        const { query } = await this.getModelQuery();
        return this.findUser(query.where(this.config.identifierKey, id));
    }
    /**
     * Returns a user instance using a specific token type and value
     */
    async findByRememberMeToken(id, value) {
        const { query } = await this.getModelQuery();
        return this.findUser(query.where(this.config.identifierKey, id).where('rememberMeToken', value));
    }
    /**
     * Returns the user instance by searching the uidValue against
     * their defined uids.
     */
    async findByUid(uidValue) {
        const model = await this.getModel();
        /**
         * Use custom function on the model. This time, we do not emit
         * an event, since the user custom lookup may not even
         * run a query at all.
         */
        if (typeof model.findForAuth === 'function') {
            const user = await model.findForAuth(this.config.uids, uidValue);
            return this.getUserFor(user);
        }
        /**
         * Lookup by running a custom query.
         */
        const { query } = await this.getModelQuery();
        this.config.uids.forEach((uid) => query.orWhere(uid, uidValue));
        return this.findUser(query);
    }
    /**
     * Updates the user remember me token. The guard must called `setRememberMeToken`
     * before invoking this method.
     */
    async updateRememberMeToken(providerUser) {
        /**
         * Extra check to find malformed guards
         */
        if (!providerUser.user.$dirty.rememberMeToken) {
            throw new Error('The guard must called "setRememberMeToken" before calling "updateRememberMeToken" on the Lucid provider');
        }
        await providerUser.user.save();
    }
}
exports.LucidProvider = LucidProvider;
