"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.DatabaseProvider = void 0;
const hooks_1 = require("@poppinss/hooks");
const utils_1 = require("@poppinss/utils");
const User_1 = require("./User");
/**
 * Database provider to lookup users inside the database
 */
class DatabaseProvider {
    constructor(application, config, db) {
        this.application = application;
        this.config = config;
        this.db = db;
        /**
         * Hooks reference
         */
        this.hooks = new hooks_1.Hooks();
        /**
         * Name of the remember_me_token column
         */
        this.rememberMeColumn = 'remember_me_token';
    }
    /**
     * Returns the query client for invoking queries
     */
    getQueryClient() {
        if (!this.connection) {
            return this.db.connection(this.config.connection);
        }
        return typeof this.connection === 'string'
            ? this.db.connection(this.connection)
            : this.connection;
    }
    /**
     * Returns the query builder instance for the users table
     */
    getUserQueryBuilder() {
        return this.getQueryClient().from(this.config.usersTable);
    }
    /**
     * Ensure "user.id" is always present
     */
    ensureUserHasId(user) {
        /**
         * Ignore when user is null
         */
        if (!user) {
            return;
        }
        if (!user[this.config.identifierKey]) {
            throw new utils_1.Exception(`Auth database provider expects "${this.config.usersTable}.${this.config.identifierKey}" to always exist`);
        }
    }
    /**
     * 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 provider user
     */
    async getUserFor(user) {
        this.ensureUserHasId(user);
        const UserBuilder = this.config.user ? (0, utils_1.esmResolver)(await this.config.user()) : User_1.DatabaseUser;
        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 the user row using the primary key
     */
    async findById(id) {
        const query = this.getUserQueryBuilder();
        return this.findUser(query.where(this.config.identifierKey, id));
    }
    /**
     * Returns a user from their remember me token
     */
    async findByRememberMeToken(id, token) {
        const query = this.getUserQueryBuilder()
            .where(this.rememberMeColumn, token)
            .where(this.config.identifierKey, id);
        return this.findUser(query);
    }
    /**
     * Returns the user row by searching the uidValue against
     * their defined uids.
     */
    async findByUid(uidValue) {
        const query = this.getUserQueryBuilder();
        this.config.uids.forEach((uid) => query.orWhere(uid, uidValue));
        return this.findUser(query);
    }
    /**
     * Updates the user remember me token
     */
    async updateRememberMeToken(user) {
        this.ensureUserHasId(user);
        await this.getUserQueryBuilder()
            .where(this.config.identifierKey, user[this.config.identifierKey])
            .update({
            remember_me_token: user.getRememberMeToken(),
        });
    }
}
exports.DatabaseProvider = DatabaseProvider;
