import { InternalService, Microservice } from "@autoplex/microservice";
import { env, secret } from "@autoplex/utils";
import { createConnection, Connection, EntitySchema } from "typeorm";
import * as DB from "./constants";
import * as entities from "./entities";

/**
 * The type for entity schemas
 */
export type EntitySchemaTypes = string|Function|EntitySchema<any>;

/**
 * A convenience database service
 */
export class DatabaseService<M extends Microservice = Microservice> extends InternalService<M>
{
	/**
	 * The name of the service
	 */
	public readonly NAME = "Database";

	/**
	 * The active database connection
	 */
	public connection!: Connection;

	/**
	 * The function used to create the connection
	 * This is important because inheriting this service to provide custom entity types will not get
	 * the connection stored in the correct connection manager without overriding this explicitly.
	 */
	protected createConnection = createConnection;

	/**
	 * The database entities
	 */
	protected entities: EntitySchemaTypes[] = Object.values(entities);

	/**
	 * Boot the database service
	 */
	public async boot() {
		let password = await secret(DB.DATABASE_PASSWORD_FILE);
		let database = env("DATABASE");
		this.connection = await this.connectToDatabase(
			DB.DATABASE_TYPE,
			DB.DATABASE_HOST,
			DB.DATABASE_PORT,
			DB.DATABASE_USER,
			password,
			database,
			this.entities
		);
	}

	/**
	 * Shutdown the database service
	 */
	public async shutdown() {
		await this.connection.close();
	}

	/**
	 * A convenience function to connect to the database
	 */
	protected async connectToDatabase(type: "mysql"|"mariadb", host: string, port: number,
	                                user: string, password: string, database: string,
	                                entities: EntitySchemaTypes[])
	{
		// Create the database connection
		return await this.createConnection({
			type       : type,
			host       : host,
			port       : port,
			username   : user,
			password   : password,
			database   : database,
			// synchronize: process.env["NODE_ENV"] != "production",
			synchronize: true, // Seems stable enough for my liking
			entities
		});
	}
}
