import { IExecuteFunctions, NodeOperationError, NodeApiError } from 'n8n-workflow';

/**
 * Handle ProxMox API errors with context-specific messages
 */
export function handleProxMoxError(
	this: IExecuteFunctions,
	error: any,
	operation: string,
	resource: string,
): never {
	let message = `Failed to ${operation} ${resource}`;

	if (error instanceof NodeApiError || error instanceof NodeOperationError) {
		throw error;
	}

	// Handle specific ProxMox error cases
	if (error.response) {
		const statusCode = error.statusCode || error.response.status;
		const errorBody = error.error || error.response.body || error.response.data;

		switch (statusCode) {
			case 400:
				message = `Bad request: Invalid parameters for ${operation} ${resource}`;
				if (errorBody?.errors) {
					const errors = Array.isArray(errorBody.errors)
						? errorBody.errors.join(', ')
						: JSON.stringify(errorBody.errors);
					message += ` - ${errors}`;
				}
				break;

			case 401:
				message = 'Authentication failed. Please check your ProxMox credentials.';
				break;

			case 403:
				message = `Permission denied. User lacks privileges to ${operation} ${resource}.`;
				break;

			case 404:
				message = `${resource} not found. Please check the resource ID or name.`;
				break;

			case 409:
				message = `Conflict: ${resource} already exists or is in an incompatible state.`;
				break;

			case 422:
				message = `Validation error for ${operation} ${resource}`;
				if (errorBody?.errors) {
					const errors = Array.isArray(errorBody.errors)
						? errorBody.errors.join(', ')
						: JSON.stringify(errorBody.errors);
					message += ` - ${errors}`;
				}
				break;

			case 500:
				message = `ProxMox server error during ${operation} ${resource}. Please try again later.`;
				break;

			case 503:
				message = `ProxMox service unavailable. The node may be busy or under maintenance.`;
				break;

			default:
				if (errorBody) {
					if (typeof errorBody === 'object') {
						if (errorBody.message) {
							message = errorBody.message;
						} else if (errorBody.reason) {
							message = errorBody.reason;
						} else if (errorBody.errors) {
							const errors = Array.isArray(errorBody.errors)
								? errorBody.errors.join(', ')
								: JSON.stringify(errorBody.errors);
							message = `Error ${operation} ${resource}: ${errors}`;
						}
					} else if (typeof errorBody === 'string') {
						message = errorBody;
					}
				}
		}
	} else if (error.message) {
		message = error.message;
	}

	throw new NodeOperationError(this.getNode(), message);
}

/**
 * Validate required parameters for ProxMox operations
 */
export function validateParameters(
	this: IExecuteFunctions,
	parameters: { [key: string]: any },
	required: string[],
	operation: string,
): void {
	const missing = required.filter((param) => !parameters[param]);

	if (missing.length > 0) {
		throw new NodeOperationError(
			this.getNode(),
			`Missing required parameters for ${operation}: ${missing.join(', ')}`,
		);
	}
}

/**
 * Validate ProxMox node name format
 */
export function validateNodeName(nodeName: string): boolean {
	// ProxMox node names should be valid hostnames
	const nodeNameRegex = /^[a-zA-Z0-9]([a-zA-Z0-9-]*[a-zA-Z0-9])?$/;
	return nodeNameRegex.test(nodeName) && nodeName.length <= 63;
}

/**
 * Validate ProxMox VM/Container ID format
 */
export function validateVmId(vmId: string | number): boolean {
	const id = typeof vmId === 'string' ? parseInt(vmId, 10) : vmId;
	return !isNaN(id) && id >= 100 && id <= 999999999;
}

/**
 * Validate ProxMox storage name format
 */
export function validateStorageName(storageName: string): boolean {
	// Storage names in ProxMox follow specific naming conventions
	const storageNameRegex = /^[a-zA-Z0-9][a-zA-Z0-9._-]*$/;
	return storageNameRegex.test(storageName) && storageName.length <= 64;
}

/**
 * Parse and validate ProxMox resource ID from various formats
 */
export function parseResourceId(resourceId: string): {
	node: string;
	type?: string;
	vmid?: number;
	storage?: string;
} {
	// Handle different ProxMox resource ID formats:
	// - node/pve (node reference)
	// - node/qemu/vmid (VM reference)
	// - node/lxc/vmid (Container reference)
	// - node/storage/storagename (Storage reference)

	const parts = resourceId.split('/');
	const result: { node: string; type?: string; vmid?: number; storage?: string } = {
		node: parts[0],
	};

	if (parts.length >= 2) {
		result.type = parts[1];

		if (parts.length >= 3) {
			if (parts[1] === 'qemu' || parts[1] === 'lxc') {
				const vmid = parseInt(parts[2], 10);
				if (isNaN(vmid)) {
					throw new Error(`Invalid VM/Container ID: ${parts[2]}`);
				}
				result.vmid = vmid;
			} else if (parts[1] === 'storage') {
				result.storage = parts[2];
			}
		}
	}

	// Validate node name
	if (!validateNodeName(result.node)) {
		throw new Error(`Invalid node name: ${result.node}`);
	}

	// Validate VM ID if present
	if (result.vmid !== undefined && !validateVmId(result.vmid)) {
		throw new Error(`Invalid VM/Container ID: ${result.vmid}`);
	}

	// Validate storage name if present
	if (result.storage !== undefined && !validateStorageName(result.storage)) {
		throw new Error(`Invalid storage name: ${result.storage}`);
	}

	return result;
}
