/*!
 * Baxxon
 * Copyright(c) 2000-2026 Lorne Taylor
 * MIT Licensed
 */

// Logger class

import fs from 'node:fs';
import path from 'node:path';

export class Logger {

	defaultOp = {
		console: true,
		level: 'all',
		msgPrefix: '[bx]'
	}

	op = {}
	log = [];

	constructor(op={}){

		this.op = { ...this.defaultOp, ...op }
	}

	banner(){

		let banner = "_____  ____  __  ____  __ ____  __  _ ";
		banner += "\n| () )/ () \\ \\ \\/ /\\ \\/ // () \\|  \\| |";
		banner += "\n|_()_)__/\\__\\/_/\\_\\/_/\\_\\\\____/|_|\\__|";
		
		if(this.op.console){
			console.log(`${banner} v${this.version()}`, "\n");
			this.note("waiting on next request...");
		}
	}

	version(){

		if(this.versionStr) return this.versionStr;

		try{
			const pkgPath = path.join(import.meta.dirname, "../package.json");
			const pkg = JSON.parse(fs.readFileSync(pkgPath, "utf8"));
			this.versionStr = pkg.version;
		}
		catch(e){
			this.versionStr = "unknown";
		}

		return this.versionStr;
	}

	versionStr = "";

	save( ...rest ){

		let msg = `${this.op.msgPrefix} `;

		for( let arg of rest ){
			if(arg !== undefined && arg !== null && arg.constructor && arg.constructor.name.includes('Error')){
				arg = "\n" + arg.stack;
			} 
			else if(typeof arg !== 'string'){ 
				arg = JSON.stringify(arg, null, 4);
			} 
			msg = msg.concat(arg, ' ');
		}

		this.log.push(msg);

		if(this.op.console){
			console.log(msg);
		}

		return msg;
	}

	getRef(){

		const err = new Error();
		const stackLine = err.stack.split('\n')[3];
		const filePath = stackLine.match(/file:(.*?):/)[1];
		var fileName = /[^/]*$/.exec(filePath)[0];
		const lineNum = stackLine.match(/:(\d+):/)[1];

		return `in ${fileName}:${lineNum}`;
	}
	
	getLast(){

		return this.log[this.log.length -1];
	}

	reportLevels = new Map();

	colorize = {

		render(color, msg){
			const reset = "\x1b[0m";
			const colors = {
				red: "\x1b[31m",
				green: "\x1b[32m",
				yellow: "\x1b[33m",
				magenta: "\x1b[35m"
			}
			return colors[color] + msg + reset;
		},
		green(msg){return this.render('green', msg)},
		red(msg){return this.render('red', msg)},
		yellow(msg){return this.render('yellow', msg)},
		magenta(msg){return this.render('magenta', msg)}
	}

	bang(...rest){

		const msg = this.save(this.colorize.magenta("*******\n"), ...rest);
	}

	note(...rest){

		const msg = this.save(...rest);
	}

	warn(...rest){

		const msg = this.save(this.colorize.yellow(":: WARNING ::\n    "), ...rest, this.getRef());
	}

	error(...rest){

		const msg = this.save(this.colorize.red(":: ERROR ::\n    "), ...rest, this.getRef());
	}

	isPrimary(req){

		if(!req) return true;
		// Heuristic for "Main" request vs "Child" request (assets)
		// 1. POST requests are usually main
		// 2. GET requests for document/page (no extension or sec-fetch-dest: document)
		const url = req.url.split('?')[0];
		const isAsset = url.includes('.');
		const isDoc = req.headers['sec-fetch-dest'] === 'document';
		
		return req.method === 'POST' || isDoc || !isAsset;
	}

	hasActiveBlock = false;

	start(req){

		if(req){
			if(this.isPrimary(req)){
				this.note("================================================");
				this.note(this.colorize.green(':: START ::'), req.method, req.url);
				this.hasActiveBlock = true;
			} else {
				this.note(this.colorize.green(':: CONT. ::'), req.method, req.url);
			}
		} else {
			this.note("::");
			this.note(":: START :::::::");
		}
	}

	end(req){
		
		this.note(this.colorize.green(":: END ::"), "waiting on next request...\n");
	}
}

// instantiate a global class
const log = new Logger
export default log;

