import { validateWorkflow } from '@n8n/workflow-sdk';
import type { WorkflowJSON } from '@n8n/workflow-sdk';

import type { WorkflowResponse } from '../../clients/n8n-client';
import type { BinaryCheck } from '../types';

/** Error codes emitted by schema validation in validateWorkflow */
const SCHEMA_ERROR_CODES = new Set(['INVALID_PARAMETER', 'MISSING_PARAMETER']);

/**
 * WorkflowResponse uses `Record<string, unknown>` for parameters/connections where
 * WorkflowJSON uses narrower type aliases (IDataObject, IConnections). The shapes
 * are structurally compatible at runtime but require a bridge cast at compile time.
 *
 * If either type drifts (e.g. WorkflowJSON gains a required field), this cast
 * will silently hide the mismatch. If that happens, replace the `as unknown as`
 * with an explicit per-field mapper and let TS enforce the shape.
 */
function toWorkflowJson(workflow: WorkflowResponse): WorkflowJSON {
	return {
		name: workflow.name,
		nodes: (workflow.nodes ?? []).map((n, i) => ({
			id: String(i),
			name: n.name,
			type: n.type,
			typeVersion: n.typeVersion ?? 1,
			parameters: n.parameters ?? {},
			position: [0, 0],
		})),
		connections: workflow.connections,
	} as unknown as WorkflowJSON;
}

/**
 * Validates node parameters against generated Zod schemas via workflow-sdk.
 *
 * Covers both:
 * - Missing required parameters (what ai-workflow-builder.ee checked as `valid_required_parameters`)
 * - Invalid option values (what ai-workflow-builder.ee checked as `valid_options_values`)
 *
 * Uses `validateWorkflow` with trigger/connectivity checks disabled (handled by
 * other binary checks), keeping only schema validation. Gracefully skips nodes
 * that have no schema available.
 */
export const validNodeConfig: BinaryCheck = {
	name: 'valid_node_config',
	description: 'Node parameters match their Zod schemas (required params, valid options)',
	kind: 'deterministic',
	dimension: 'parameter_correctness',
	run(workflow: WorkflowResponse) {
		const nodes = workflow.nodes ?? [];
		if (nodes.length === 0) return { pass: true };

		const result = validateWorkflow(toWorkflowJson(workflow), {
			allowNoTrigger: true,
			allowDisconnectedNodes: true,
			validateSchema: true,
		});

		// Only report schema-level errors, not structural warnings
		const schemaErrors = result.errors.filter((e) => SCHEMA_ERROR_CODES.has(e.code));

		if (schemaErrors.length === 0) return { pass: true };

		const messages = schemaErrors.map((e) => `${e.nodeName ? `${e.nodeName}: ` : ''}${e.message}`);

		return { pass: false, comment: messages.join('; ') };
	},
};
