import { flags } from '@oclif/command';
import { SecurityAuditService } from '@/security-audit/SecurityAudit.service';
import { RISK_CATEGORIES } from '@/security-audit/constants';
import config from '@/config';
import type { Risk } from '@/security-audit/types';
import { BaseCommand } from './BaseCommand';
import { Container } from 'typedi';
import { InternalHooks } from '@/InternalHooks';
import { ApplicationError } from 'n8n-workflow';

export class SecurityAudit extends BaseCommand {
	static description = 'Generate a security audit report for this n8n instance';

	static examples = [
		'$ n8n audit',
		'$ n8n audit --categories=database,credentials',
		'$ n8n audit --days-abandoned-workflow=10',
	];

	static flags = {
		help: flags.help({ char: 'h' }),
		categories: flags.string({
			default: RISK_CATEGORIES.join(','),
			description: 'Comma-separated list of categories to include in the audit',
		}),
		// eslint-disable-next-line @typescript-eslint/naming-convention
		'days-abandoned-workflow': flags.integer({
			default: config.getEnv('security.audit.daysAbandonedWorkflow'),
			description: 'Days for a workflow to be considered abandoned if not executed',
		}),
	};

	async run() {
		const { flags: auditFlags } = this.parse(SecurityAudit);

		const categories =
			auditFlags.categories?.split(',').filter((c): c is Risk.Category => c !== '') ??
			RISK_CATEGORIES;

		const invalidCategories = categories.filter((c) => !RISK_CATEGORIES.includes(c));

		if (invalidCategories.length > 0) {
			const message =
				invalidCategories.length > 1
					? `Invalid categories received: ${invalidCategories.join(', ')}`
					: `Invalid category received: ${invalidCategories[0]}`;

			const hint = `Valid categories are: ${RISK_CATEGORIES.join(', ')}`;

			throw new ApplicationError([message, hint].join('. '));
		}

		const result = await Container.get(SecurityAuditService).run(
			categories,
			auditFlags['days-abandoned-workflow'],
		);

		if (Array.isArray(result) && result.length === 0) {
			this.logger.info('No security issues found');
		} else {
			process.stdout.write(JSON.stringify(result, null, 2));
		}

		void Container.get(InternalHooks).onAuditGeneratedViaCli();
	}

	async catch(error: Error) {
		this.logger.error('Failed to generate security audit');
		this.logger.error(error.message);
	}
}
