import { nanoid } from 'nanoid';

import type { n8nPage } from '../pages/n8nPage';

/**
 * A class for user interactions with workflows that go across multiple pages.
 */
export class WorkflowComposer {
	constructor(private readonly n8n: n8nPage) {}

	/**
	 * Executes a successful workflow and waits for the notification to be closed.
	 * This waits for http calls and also closes the notification.
	 */
	async executeWorkflowAndWaitForNotification(
		notificationMessage: string,
		options: { timeout?: number } = {},
	) {
		const { timeout = 3000 } = options;
		const responsePromise = this.n8n.page.waitForResponse(
			(response) =>
				response.url().includes('/rest/workflows/') &&
				response.url().includes('/run') &&
				response.request().method() === 'POST',
		);

		await this.n8n.canvas.clickExecuteWorkflowButton();
		await responsePromise;
		await this.n8n.notifications.waitForNotificationAndClose(notificationMessage, { timeout });
	}

	/**
	 * Creates a new workflow by clicking the add workflow button and setting the name
	 * @param workflowName - The name of the workflow to create
	 */
	async createWorkflow(workflowName = 'My New Workflow') {
		await this.n8n.workflows.clickAddWorkflowButton();
		await this.n8n.canvas.setWorkflowName(workflowName);

		const responsePromise = this.n8n.page.waitForResponse(
			(response) =>
				response.url().includes('/rest/workflows') && response.request().method() === 'POST',
		);
		await this.n8n.canvas.saveWorkflow();

		await responsePromise;
	}

	/**
	 * Creates a new workflow by importing a JSON file
	 * @param fileName - The workflow JSON file name (e.g., 'test_pdf_workflow.json', will search in workflows folder)
	 * @param name - Optional custom name. If not provided, generates a unique name
	 * @returns The actual workflow name that was used
	 */
	async createWorkflowFromJsonFile(
		fileName: string,
		name?: string,
	): Promise<{ workflowName: string }> {
		const workflowName = name ?? `Imported Workflow ${nanoid(8)}`;
		await this.n8n.goHome();
		await this.n8n.workflows.clickAddWorkflowButton();
		await this.n8n.canvas.importWorkflow(fileName, workflowName);
		return { workflowName };
	}

	/**
	 * Creates a new workflow by importing from a URL
	 * @param url - The URL to import the workflow from
	 * @returns Promise that resolves when the import is complete
	 */
	async importWorkflowFromURL(url: string): Promise<void> {
		await this.n8n.workflows.clickAddWorkflowButton();
		await this.n8n.canvas.clickWorkflowMenu();
		await this.n8n.canvas.clickImportFromURL();
		await this.n8n.canvas.fillImportURLInput(url);
		await this.n8n.canvas.clickConfirmImportURL();
	}

	/**
	 * Opens the import from URL dialog and then dismisses it by clicking outside
	 */
	async openAndDismissImportFromURLDialog(): Promise<void> {
		await this.n8n.workflows.clickAddWorkflowButton();
		await this.n8n.canvas.clickWorkflowMenu();
		await this.n8n.canvas.clickImportFromURL();
		await this.n8n.canvas.clickOutsideModal();
	}

	/**
	 * Opens the import from URL dialog and then cancels it
	 */
	async openAndCancelImportFromURLDialog(): Promise<void> {
		await this.n8n.workflows.clickAddWorkflowButton();
		await this.n8n.canvas.clickWorkflowMenu();
		await this.n8n.canvas.clickImportFromURL();
		await this.n8n.canvas.clickCancelImportURL();
	}
}
