import { Sequelize } from 'sequelize';
import { LoggingService } from '#services/file-system/logService';

const logger = new LoggingService();

export interface PoolConfig {
	username: string;
	password: string;
	database: string;
	host: string;
	port: number;
	pool?: {
		max: number;
		min: number;
		acquire: number;
		idle: number;
		evict: number;
	};
	slowQueryThresholdMs?: number;
}

const slowQueryThresholdMs = 500;

export class MultiPoolService {
	private static readonly pools = new Map<string, Sequelize>();

	static getPool(name: string): Sequelize {
		const existing = this.pools.get(name);
		if (existing) return existing;

		throw new Error(`Pool '${name}' not found. Did you call createPool() first?`);
	}

	static hasPool(name: string): boolean {
		return this.pools.has(name);
	}

	static createPool(name: string, config: PoolConfig): Sequelize {
		const existing = this.pools.get(name);
		if (existing) {
			void existing.close();
			this.pools.delete(name);
		}

		const pool = config.pool ?? { max: 20, min: 2, acquire: 30000, idle: 10000, evict: 60000 };

		const sequelize = new Sequelize({
			username: config.username,
			password: config.password,
			database: config.database,
			host: config.host,
			port: config.port,
			dialect: 'postgres',
			pool: {
				max: pool.max,
				min: pool.min,
				acquire: pool.acquire,
				idle: pool.idle,
				evict: pool.evict,
			},
			benchmark: true,
			logging(sql, timing) {
				const durationMs = typeof timing === 'number' ? timing : null;
				if (durationMs !== null && durationMs >= (config.slowQueryThresholdMs ?? slowQueryThresholdMs)) {
					void logger.logAsync('slow_query', 'Sequelize', `[${durationMs}ms] ${sql}`, null);
				} else {
					void logger.logDBAsync(sql);
				}
			},
		});

		this.pools.set(name, sequelize);
		return sequelize;
	}

	static async closeAll(): Promise<void> {
		await Promise.all([...this.pools.values()].map((pool) => pool.close()));
		this.pools.clear();
	}

	static async healthCheck(name: string): Promise<boolean> {
		const pool = this.pools.get(name);
		if (!pool) return false;
		try {
			await pool.authenticate();
			return true;
		} catch {
			return false;
		}
	}

	static listPools(): string[] {
		return [...this.pools.keys()];
	}
}
