import {
	IExecuteFunctions,
	INodeExecutionData,
	INodeType,
	INodeTypeDescription,
} from 'n8n-workflow';

// We might need uuid for client ID generation later
// import { v4 as uuidv4 } from 'uuid';

export class ComfyUiRunner implements INodeType {
	description: INodeTypeDescription = {
		displayName: 'ComfyUI Runner',
		name: 'comfyUiRunner',
		// Changed group to something more appropriate
		group: ['External APIs'],
		version: 1,
		description: 'Runs a ComfyUI workflow via its API', // Updated description
		defaults: {
			name: 'ComfyUI Runner', // Updated default name
		},
		inputs: ['main'] as any,
		outputs: ['main'] as any,
		properties: [
			// Property for the ComfyUI API URL
			{
				displayName: 'ComfyUI URL',
				name: 'comfyUiUrl',
				type: 'string',
				default: 'http://127.0.0.1:8188',
				placeholder: 'http://127.0.0.1:8188',
				description: 'The base URL of your running ComfyUI instance (e.g., http://localhost:8188)',
				required: true,
			},
			// Property for the Workflow JSON
			{
				displayName: 'Workflow JSON',
				name: 'workflowJson',
				type: 'json', // Use 'json' type for better input validation and expression support
				default: '{}',
				placeholder: 'Paste your ComfyUI API format workflow here',
				description: 'The ComfyUI workflow in API JSON format. Use expressions to insert dynamic data.',
				required: true,
				// Optional: Enhance the JSON editor experience
				// typeOptions: {
				// 	editor: 'json',
				// 	language: 'json',
				// },
			},
		],
	};

	// The execute method will be defined below
	async execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]> {
		const items = this.getInputData();
		const returnData: INodeExecutionData[] = [];

		// Loop through each input item
		for (let itemIndex = 0; itemIndex < items.length; itemIndex++) {
			try {
				// Get node parameters for the current item
				const comfyUiUrl = this.getNodeParameter('comfyUiUrl', itemIndex, '') as string;
				// Get the workflow JSON, allowing for expressions
				const workflowJsonString = this.getNodeParameter('workflowJson', itemIndex, '{}') as string;

				// --- Placeholder for ComfyUI API Interaction ---
				// This section will contain the logic to:
				// 1. Parse workflowJsonString into a JavaScript object.
				//    let workflowObject = JSON.parse(workflowJsonString);
				// 2. Generate a unique client ID (e.g., using uuid).
				//    const clientId = uuidv4();
				// 3. Establish a WebSocket connection to `${comfyUiUrl}/ws?clientId=${clientId}`.
				//    - Use a library like 'ws'. Remember to add it as a dependency if needed.
				// 4. Send the workflow via a POST request to `${comfyUiUrl}/prompt`.
				//    - The body should be { prompt: workflowObject, client_id: clientId }.
				//    - Use `this.helpers.httpRequest` for the POST request.
				// 5. Listen for messages on the WebSocket connection:
				//    - Handle 'status' messages (queue updates).
				//    - Handle 'execution_start' message.
				//    - Handle 'executing' messages (current node, check for errors).
				//    - Handle 'progress' messages (optional).
				//    - Wait for the 'executed' message which contains output data, including image details (filename, subfolder, type).
				//    - Close the WebSocket connection when done or on error.
				// 6. Once the 'executed' message with image details is received:
				//    - Construct the image URL: `${comfyUiUrl}/view?filename=${filename}&subfolder=${subfolder}&type=${type}`.
				//    - Fetch the image data using `this.helpers.httpRequest`. Crucially, set `returnBinaryData: true` and `encoding: 'arraybuffer'`.
				//      const imageDataBuffer = await this.helpers.httpRequest({ ...options... });
				// 7. Prepare the output item for n8n:
				//    - Create binary data using `this.helpers.prepareBinaryData`.
				//      const binaryOutput: IBinaryData = await this.helpers.prepareBinaryData(
				//          Buffer.from(imageDataBuffer), // Convert ArrayBuffer to Buffer
				//          'output.png' // Or use the filename from ComfyUI
				//      );
				//    - Construct the final INodeExecutionData object.
				//      const newItem: INodeExecutionData = {
				//          json: { success: true, message: "Workflow executed", outputFilename: filename }, // Example JSON output
				//          binary: { data: binaryOutput }, // Attach the binary data under a key (e.g., 'data')
				//          pairedItem: { item: itemIndex },
				//      };
				//      returnData.push(newItem);
				// --- End Placeholder ---

				// For now, just return a success message and pass through input JSON.
				// We will replace this with the actual API logic later.
				const newItem: INodeExecutionData = {
					json: {
						...items[itemIndex].json, // Pass original JSON through
						_comfyRunnerStatus: 'Placeholder - API call not implemented yet',
						_receivedUrl: comfyUiUrl,
						_receivedWorkflow: workflowJsonString, // Show what was received
					},
					binary: {}, // No binary data yet
					pairedItem: { item: itemIndex },
				};
				returnData.push(newItem);

			} catch (error: any) {
				// Handle errors for individual items
				if (this.continueOnFail()) {
					const errorItem: INodeExecutionData = {
						json: {
							error: error.message,
							stack: error.stack, // Include stack trace for debugging
							itemIndex: itemIndex,
							inputJson: items[itemIndex].json, // Include original input for context
						},
						binary: {},
						pairedItem: { item: itemIndex },
					};
					returnData.push(errorItem);
					continue; // Continue to the next item
				}
				// If not continuing on fail, re-throw the error to stop the workflow
				throw error;
			}
		}

		// Return the processed data
		return this.prepareOutputData(returnData);
	}
}
