#!/usr/bin/env node --no-warnings
import { dirname } from 'path';
import { fileURLToPath } from 'url';
import { existsSync } from 'fs';
import chalk from 'chalk';
import settings from './settings.json' assert { type: 'json' };
import projectPackageJSON from '../package.json' assert { type: 'json' };

import { join } from 'path';
import fs from 'fs/promises';

import { init } from './init.js';
import { sync } from './sync.js';
import { runGulp, installPackages, killAllProcesses, cleanupWatchers } from './helpers.js';
import { prepare } from './prepare.js';
import { spawnSync } from 'child_process';

export type LucySettings = {
	modules: {
		[llibName: string]: {
			url: string;
			branch: string;
		};
	};
	wixSettings: {
		compilerOptions: {
			composite: boolean;
			noEmit: boolean;
			lib: string[];
			jsx: string;
		};
		exclude: string[];
	};
	initialized: boolean;
	wixPackages: {
		[packageName: string]: string;
	};
	devPackages: {
		[packageName: string]: string;
	};
	scripts: {
		[commandName: string]: string;
	};
};

export type ModuleSettings = {
	packageRoot: string;
	targetFolder: string;
	args: string[];
	wixConfigPath: string;
	lucyConfigPath: string;
	packageJsonPath: string;
	settings: LucySettings;
	lockVersion: boolean;
	force: boolean;
	veloConfigName: string;
}

export type ProjectSettings = {
	// packages?: Record<string, string>;
	modules?: Record<string, string>;
	lucySettings?: LucySettings;
	packageJSON?: Record<string, any>;
}

export const orange = chalk.hex('#FFA500');
export const blue = chalk.blueBright;
export const green = chalk.greenBright;
export const red = chalk.redBright;
export const yellow = chalk.yellow;
export const magenta = chalk.magentaBright;

// eslint-disable-next-line @typescript-eslint/naming-convention
const __filename = fileURLToPath(import.meta.url);
// eslint-disable-next-line @typescript-eslint/naming-convention
const __dirname = dirname(__filename);

// const cwd = process.cwd();
// const command = `watchman watch-del '${cwd}'`;
// killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
// killAllProcesses('wix:dev');   


process.on('exit', (code) => {
	killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
	killAllProcesses('wix:dev');   
    cleanupWatchers();
	console.log(`🚪 ${magenta.underline('Process exiting with code:')} ${orange(code)}`);
});

process.on('SIGINT', () => {
	console.log(`🐕 ${green.underline('Received Ctrl+C (SIGINT), cleaning up...')}`);
	killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
	killAllProcesses('wix:dev');  
    cleanupWatchers();
    process.exit(); // Exit explicitly after handling
});

process.on('SIGTERM', () => {
	console.log(`🛑 ${red.underline('Received termination signal (SIGTERM), cleaning up...')}`);
	killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
	killAllProcesses('wix:dev');  
    cleanupWatchers();
    process.exit(); // Exit explicitly after handling
});

process.on('uncaughtException', (error) => {
	console.error(`💥 ${red.underline('Uncaught Exception:')}`, error);
	killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
	killAllProcesses('wix:dev');  
    cleanupWatchers();
    process.exit(1); // Exit with an error code
});

process.on('unhandledRejection', (reason, promise) => {
	console.error(`🚨 ${yellow.underline('Unhandled Rejection at:')} ${orange(promise)}`);
	console.error(`🚨 ${red.underline('Reason:')} ${reason}`);    cleanupWatchers();
	killAllProcesses('@wix/cli/bin/wix.cjs'); // Matches processes running the Wix CLI
	killAllProcesses('wix:dev');  
    cleanupWatchers();
    process.exit(1); // Exit with an error code
});

/**
 * Main function
 * @returns {Promise<void>}
 */
async function main(): Promise<void> {
	// INFO: Module settings
	const moduleSettings: ModuleSettings = {
		packageRoot: dirname(__dirname),
		targetFolder: process.cwd(),
		args:  process.argv.slice(2),
		settings,
		wixConfigPath: join(process.cwd(), 'wix.config.json'),
		lucyConfigPath: join(process.cwd(), 'lucy.json'),
		packageJsonPath: join(process.cwd(), 'package.json'),
		force: false,
		lockVersion: false,
		veloConfigName: 'config.json'
	}

	let projectSettings: ProjectSettings = {}; 

	if(moduleSettings.args.includes('version') || moduleSettings.args.includes('-v')){
		console.log("🐾" + blue.bold(` => ${projectPackageJSON.version}`));
        
		return;
	}
	// Run velo sync
	if(moduleSettings.args.includes('velo-sync')){
		await sync(moduleSettings, projectSettings);

		return;
	}

	if(moduleSettings.args.includes('help') || moduleSettings.args.includes('-h')){
		console.log("🦮 " + green.underline.bold(' => Lucy CLI Help'));
		console.log("Usage: lucy-cli <command> [options]");
		console.log("\nCommands:");
		console.log("🦮 " + magenta.bold('init') + "               : Initializes caontaining a WIX project to enable full TS support");
		console.log("🦮 " + magenta.bold('dev') + "                : Starts the development environment. This includes setting up any required services for local development.");
		console.log("🦮 " + magenta.bold('build-prod') + "         : Builds the project in production mode, optimizing files for deployment.");
		console.log("🦮 " + magenta.bold('prepare') + "            : Prepares the project by installing packages & initializing git modules, configured in lucy.json");
		console.log("🦮 " + magenta.bold('velo-sync') + "          : Synchronizes wix collections(velo-sync -h for help)");
		console.log("🦮 " + magenta.bold('install') + "            : Installs all Wix npm packages listed in the 'lucy.json' file in the project directory.");
		console.log("🦮 " + magenta.bold('fix') + "                : Runs a fix command to resolve common issues in development or production settings.");
		console.log("🦮 " + magenta.bold('docs') + "               : Generates documentation for the project.");
		console.log("🦮 " + magenta.bold('cypress') + "            : Starts the cypress test runner.");
		console.log("🦮 " + magenta.bold('e2e') + "                : Starts the cypress test runner in CI mode. first argument is the key second is the build id <e2e <somekey <someID>");
		console.log("\nOptions:");
		console.log("🦮 " + magenta.bold('-h, help') + "           : Displays this help message.");
		console.log("🦮 " + magenta.bold('-v, version') + "        : Displays the current version of Lucy CLI as defined in the project’s package.json.");
		console.log("🦮 " + magenta.bold('-f, force') + "          : Forces specific commands to execute even if they may lead to potential issues.");
		console.log("                      Used for functions like deleting obsolete pages or initializing missing components.");
		console.log("🦮 " + magenta.bold('-l') + "                  : Locks package versions to those specified in the configuration file lucy.json");
		console.log("\nExamples:");
		console.log("🦮 " + magenta.bold('lucy-cli init') + "       : Initializes a new Wix project.");
		console.log("🦮 " + magenta.bold('lucy-cli dev') + "        : Starts the development environment.");
		console.log("🦮 " + magenta.bold('lucy-cli sync') + "       : Synchronizes database and settings.");
		console.log("🦮 " + magenta.bold('lucy-cli install') + "    : Installs all Wix npm packages from 'lucy.json'.");
		console.log("🦮 " + magenta.bold('lucy-cli dev -f') + "     : Starts the dev environment with forced settings.");
		console.log("🦮 " + magenta.bold('lucy-cli install -l') + " : Installs Wix npm packages, respecting locked versions specified in the configuration.");
        
		return;
	}

	if (!existsSync(moduleSettings.wixConfigPath)) {
		console.log((`💩 ${red.underline.bold("=> This is not a WIX project =>")} ${orange(moduleSettings.targetFolder)}`));
		return;
    }

	//INFO: Collect project settings
	if(moduleSettings.args.includes('-f')) moduleSettings.force = true;
	if(moduleSettings.args.includes('-l')) moduleSettings.lockVersion = true;

	if(existsSync(moduleSettings.packageJsonPath)) {
		const packageJSONraw = await fs.readFile(join(moduleSettings.packageJsonPath), 'utf8');
		try {
			projectSettings.packageJSON = JSON.parse(packageJSONraw);
			if(moduleSettings.force) {
				console.log("❗️" + red.underline(' => Forcing'));
				moduleSettings.force = true;
			}
		} catch (parseError) {
			console.log((`💩 ${red.underline.bold("=> Error parsing package.json =>")} ${orange(parseError)}`));
			return;
		}
	}

	if(existsSync(moduleSettings.lucyConfigPath)) {
		try {
			const data = await fs.readFile(moduleSettings.lucyConfigPath, 'utf8');
			projectSettings.lucySettings = JSON.parse(data);
		} catch (parseError) {
			console.log((`💩 ${red.underline.bold("=> Error parsing Lucy.json =>")} ${orange(parseError)}`));
		}
	} else {
		if(!moduleSettings.args.includes('init')) {
			return console.log(yellow.underline.bold('🐶 => Project not Initialized! Please initialize using "lucy-cli init"'));
		};
	}
    
	if(!projectSettings.lucySettings?.initialized) {
		if(!moduleSettings.args.includes('init')) {
			return console.log(yellow.underline.bold('🐶 => Project not Initialized! Please initialize using "lucy-cli init"'));
		}
	}

	if(moduleSettings.args.includes('-l')) moduleSettings.lockVersion = true;

	console.log("🐕" + magenta.underline(' => Lucy CLI => RUNNING: ' + orange('Press Ctrl+C to stop.')));
	// INFO: Run commands

	if(moduleSettings.args.includes('init')){
		if(projectSettings.lucySettings?.initialized && !moduleSettings.force) {
			console.log((`💩 ${red.underline.bold("=> This project is already initialized =>")} ${orange(moduleSettings.targetFolder)}`));
			console.log("🐕" + magenta.underline(' => Use -f to force initialization'));
			return;
		}
		console.log("🐕" + magenta.underline(' => Initializing project'));
		init(moduleSettings, projectSettings);
		
		return;
	}


	if(moduleSettings.args.includes('docs')){
		const res = spawnSync('yarn docs', { shell: true, stdio: 'inherit' });
		if (res.error) {
			return console.log((`💩 ${red.underline.bold("=> Failed to Docs generated => ")} ${orange(res.error.message)}`));
		}
		return console.log("🐕" + blue.underline(` => Docs generated!`));
	}

	if(moduleSettings.args.includes('cypress')){
		const res = spawnSync('yarn cypress', { shell: true, stdio: 'inherit' });
		if (res.error) {
			return console.log((`💩 ${red.underline.bold("=> Failed to start cypress => ")} ${orange(res.error.message)}`));
		}
		return console.log("🐕" + blue.underline(` => Started Cypress`));
	}

	if (moduleSettings.args.includes('e2e')) {
		// Extract arguments
		const e2eIndex = moduleSettings.args.indexOf('e2e');
		const key = moduleSettings.args[e2eIndex + 1];
		const buildId = moduleSettings.args[e2eIndex + 2];
	
		// Validate that both arguments are provided
		if (!key && !buildId) {
			console.log(`💩 ${red.underline.bold("=> Missing required arguments:")} ${orange("key")} and ${orange("build ID")}`);
			process.exit(1);
		}
	
		// Run Cypress with the provided arguments
		const res = spawnSync(`yarn e2e --key ${key} --ci-build-id ${buildId}`, { shell: true, stdio: 'inherit' });
		if (res.error) {
			console.log(`💩 ${red.underline.bold("=> Failed to start Cypress =>")} ${orange(res.error.message)}`);
			process.exit(1);
		}
		return console.log("🐕 " + blue.underline(`=> Started Cypress successfully`));
	}

	if(moduleSettings.args.includes('prepare')){
		await prepare( moduleSettings, projectSettings);

		return;
	}

	if(moduleSettings.args.includes('install')){
		if(!projectSettings.lucySettings?.initialized) {
			console.log((`💩 ${red.underline.bold("=> This project is not initialized =>")} ${orange(moduleSettings.targetFolder)}`));
			console.log("🐕" + magenta.underline(' => Use init to initialize'));
			return;
		}
		await installPackages(projectSettings.lucySettings.wixPackages, projectSettings.lucySettings.devPackages, moduleSettings.targetFolder, moduleSettings.lockVersion);

		return;
	}


	if(moduleSettings.args.includes('dev')){
		runGulp(moduleSettings, projectSettings, 'dev');

		return;	
	}
	if(moduleSettings.args.includes('build-prod')){
		runGulp(moduleSettings, projectSettings, 'build-prod');

		return;	
	}
	if(moduleSettings.args.includes('fix')){
		runGulp(moduleSettings, projectSettings, 'fix-wix');

		return;	
	}

	console.log("🐕" + blue.underline.bold(' => Running dev'));
	runGulp(moduleSettings, projectSettings, 'dev');
}

main();