/*
 * @adonisjs/lucid
 *
 * (c) AdonisJS
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */
import { BaseTransformer } from '@adonisjs/core/transformers';
import { Database } from "../src/database/main.js";
import { Adapter } from "../src/orm/adapter/index.js";
import { BaseModel } from "../src/orm/base_model/index.js";
import { QueryClient } from "../src/query_client/index.js";
import { DatabaseTestUtils } from '../src/test_utils/database.js';
import { defineTransformerBindings } from "../src/bindings/transformer.js";
/**
 * AdonisJS service provider that wires up the entire Lucid ORM layer.
 *
 * Responsibilities:
 * - Registers the {@link Database} singleton and the default
 *   {@link QueryClient} in the IoC container.
 * - Attaches the ORM {@link Adapter} to {@link BaseModel}.
 * - Registers the `db` macro on {@link TestUtils} for test helpers.
 * - Binds REPL helpers when running in the `repl` environment.
 * - Registers the `unique` / `exists` VineJS validation rules when
 *   VineJS is present.
 * - Optionally enables pretty-printed debug query logging.
 *
 * @example
 * // providers/database_provider.ts is auto-discovered by AdonisJS.
 * // No manual instantiation is required.
 */
export default class DatabaseServiceProvider {
    app;
    /**
     * @param {ApplicationService} app - The AdonisJS application instance
     *   used to access the IoC container, configuration, and environment
     *   information.
     */
    constructor(app) {
        this.app = app;
    }
    /**
     * Registers REPL bindings so that interactive database helpers
     * (e.g. `db`, `User`) are available when the application is
     * started with `node ace repl`.
     *
     * This is a no-op in any environment other than `repl`.
     */
    async registerReplBindings() {
        if (this.app.getEnvironment() === 'repl') {
            const { defineReplBindings } = await import('../src/bindings/repl.js');
            defineReplBindings(this.app, await this.app.container.make('repl'));
        }
    }
    /**
     * Registers the database-backed `unique` and `exists` validation
     * rules on VineJS when the application is using VineJS as its
     * validation engine.
     *
     * This is a no-op when VineJS is not installed or configured.
     *
     * @param {Database} db - The resolved {@link Database} singleton
     *   that will be passed into the validation rule implementations.
     */
    async registerVineJSRules(db) {
        if (this.app.usingVineJS) {
            const { defineValidationRules } = await import('../src/bindings/vinejs.js');
            defineValidationRules(db);
        }
        defineTransformerBindings(BaseTransformer);
    }
    /**
     * Registers a `db` macro on the core {@link TestUtils} class.
     * The macro is lazily set up via `container.resolving('testUtils')`
     * so it is only wired when tests actually request the `testUtils`
     * binding.
     *
     * @example
     * // Inside a test file
     * const { db } = await TestUtils.create(app)
     * await db.migrate()
     */
    async registerTestUtils() {
        this.app.container.resolving('testUtils', async () => {
            const { TestUtils } = await import('@adonisjs/core/test_utils');
            TestUtils.macro('db', (connectionName) => {
                return new DatabaseTestUtils(this.app, connectionName);
            });
        });
    }
    /**
     * Attaches a listener to the `db:query` event that pretty-prints
     * every executed query to the console. Only active when the
     * `prettyPrintDebugQueries` flag is enabled in the `database.ts`
     * configuration file.
     *
     * @param {Database} db - The resolved {@link Database} singleton
     *   whose config is checked and whose `prettyPrint` handler is used.
     */
    async prettyPrintDebugQueries(db) {
        if (db.config.prettyPrintDebugQueries) {
            const emitter = await this.app.container.make('emitter');
            emitter.on('db:query', db.prettyPrint);
        }
    }
    /**
     * Lifecycle hook invoked by AdonisJS during the **register** phase.
     *
     * Registers the following singletons in the IoC container:
     * - `Database` (also aliased as `lucid.db`) — the central connection
     *   manager, built from the `database` config key.
     * - `QueryClient` — a query client bound to the **default**
     *   connection, convenient for simple queries without explicitly
     *   choosing a connection.
     */
    register() {
        this.app.container.singleton(Database, async (resolver) => {
            const config = this.app.config.get('database');
            const emitter = await resolver.make('emitter');
            const logger = await resolver.make('logger');
            const db = new Database(config, logger, emitter);
            return db;
        });
        this.app.container.singleton(QueryClient, async (resolver) => {
            const db = await resolver.make('lucid.db');
            return db.connection();
        });
        this.app.container.alias('lucid.db', Database);
    }
    /**
     * Lifecycle hook invoked by AdonisJS during the **boot** phase,
     * after all providers have registered their bindings.
     *
     * - Sets the ORM {@link Adapter} on {@link BaseModel} so that all
     *   model classes share a single, application-scoped adapter.
     * - Calls the remaining setup helpers: debug query logging, test
     *   utilities, REPL bindings, and VineJS rules.
     */
    async boot() {
        const db = await this.app.container.make('lucid.db');
        BaseModel.$adapter = new Adapter(db);
        await this.prettyPrintDebugQueries(db);
        await this.registerTestUtils();
        await this.registerReplBindings();
        await this.registerVineJSRules(db);
    }
    /**
     * Lifecycle hook invoked by AdonisJS during application shutdown.
     *
     * Gracefully closes **all** open database connections managed by the
     * {@link Database} connection manager so that no sockets or pools
     * are left dangling.
     */
    async shutdown() {
        const db = await this.app.container.make('lucid.db');
        await db.manager.closeAll();
    }
}
