// methods/configuration/ap/apSpecialized.methods.ts
import { IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
import { apiRequest } from '../../../helpers/apiRequest';
import { formatResponse } from '../../../helpers/responseFormatter';

/**
 * Normalize serial number to uppercase
 */
function normalizeSerial(serial: string): string {
	return serial.toUpperCase();
}

/**
 * Get AP settings safely with fallbacks
 */
async function getApSettings(
	executeFunctions: IExecuteFunctions,
	serialNumber: string,
): Promise<string[]> {
	// Normalize serial number to uppercase
	serialNumber = normalizeSerial(serialNumber);

	try {
		// First try the standard endpoint
		const endpoint = `/configuration/v1/ap_settings_cli/${serialNumber}`;
		const settings = await apiRequest.call(executeFunctions, 'GET', endpoint);

		if (Array.isArray(settings)) {
			return settings;
		}

		throw new Error('Unexpected response format');
	} catch (err) {
		console.log(`Error getting settings via standard endpoint: ${err.message}`);

		// Create a minimal template as fallback
		return [
			`per-ap-settings ${serialNumber}`,
			`  swarm-mode cluster`,
			`  wifi0-mode access`,
			`  wifi1-mode access`,
		];
	}
}

/**
 * Update AP settings with a specific configuration
 * This eliminates any issues with string comparison by directly working with array indices
 */
function updateApSetting(settings: string[], settingKey: string, newValue: string): string[] {
	// Create a new array for the result
	const result: string[] = [];

	// Track if we've processed the setting already to avoid duplicates
	let settingProcessed = false;

	// Stringify for clear logging
	console.log(`Starting update for setting "${settingKey}" with value "${newValue}"`);
	console.log(`Current settings (${settings.length} lines):`);
	settings.forEach((line, i) => console.log(`  ${i}: "${line}"`));

	// First line is always the per-ap-settings line
	result.push(settings[0]);

	// Flag to track if we added the new setting
	let settingAdded = false;

	// Process each line after the first one
	for (let i = 1; i < settings.length; i++) {
		const line = settings[i];

		// Check if this is the setting line we want to replace
		// Format: "  settingKey value"
		// Using exact key comparison after extracting it from the line
		const trimmed = line.trim();
		const parts = trimmed.split(' ');
		const currentKey = parts[0];

		if (currentKey === settingKey) {
			// Skip if already processed (avoiding duplicates)
			if (settingProcessed) {
				console.log(`Skipping duplicate setting at line ${i}: "${line}"`);
				continue;
			}

			// Found the setting, replace it
			console.log(`Replacing setting at line ${i}: "${line}" with "${newValue}"`);
			result.push(newValue);
			settingAdded = true;
			settingProcessed = true;
		} else {
			// Keep other lines
			result.push(line);
		}
	}

	// If setting wasn't found, add it after the first line
	if (!settingAdded) {
		console.log(`Setting not found, adding "${newValue}" after first line`);
		result.splice(1, 0, newValue);
	}

	// Log the result for debugging
	console.log(`Updated settings (${result.length} lines):`);
	result.forEach((line, i) => console.log(`  ${i}: "${line}"`));

	return result;
}

/**
 * Set AP hostname
 */
export async function setApHostname(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
	try {
		let serialNumber = this.getNodeParameter('serialNumber', 0) as string;
		const hostname = this.getNodeParameter('hostname', 0) as string;

		if (!serialNumber || !hostname) {
			throw new Error('Serial number and hostname are required');
		}

		// Normalize serial number to uppercase
		serialNumber = normalizeSerial(serialNumber);

		console.log(`Setting hostname to "${hostname}" for AP with serial: ${serialNumber}`);

		// Get current settings
		const currentSettings = await getApSettings(this, serialNumber);

		// Format the new hostname line with proper indentation
		const newHostnameLine = `  hostname ${hostname}`;

		// Update settings with new hostname using our bulletproof method
		const updatedSettings = updateApSetting(currentSettings, 'hostname', newHostnameLine);

		// Update configuration
		const endpoint = `/configuration/v1/ap_settings_cli/${serialNumber}`;
		const body = { clis: updatedSettings };

		const response = await apiRequest.call(this, 'POST', endpoint, body);
		console.log('API Response for setApHostname:', response);

		return formatResponse({
			success: true,
			message: `Hostname updated to "${hostname}" for AP ${serialNumber}`,
			updatedSettings: updatedSettings,
		});
	} catch (error) {
		console.log('ERROR in setApHostname:', error);
		throw error;
	}
}

/**
 * Set AP SSIDs (zonename)
 */
export async function setApSsids(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
	try {
		let serialNumber = this.getNodeParameter('serialNumber', 0) as string;
		const ssids = this.getNodeParameter('ssids', 0) as string[];

		if (!serialNumber || !ssids || ssids.length === 0) {
			throw new Error('Serial number and at least one SSID are required');
		}

		// Normalize serial number to uppercase
		serialNumber = normalizeSerial(serialNumber);

		console.log(`Setting SSIDs for AP with serial: ${serialNumber}`);
		console.log(`SSIDs: ${ssids.join(', ')}`);

		// Get current settings
		const currentSettings = await getApSettings(this, serialNumber);

		// Format SSIDs as comma-separated list with proper quotes
		const ssidString = ssids.join(',');
		const newZonenameLine = `  zonename "${ssidString}"`;

		// Update settings with new SSIDs
		const updatedSettings = updateApSetting(currentSettings, 'zonename', newZonenameLine);

		// Update configuration
		const endpoint = `/configuration/v1/ap_settings_cli/${serialNumber}`;
		const body = { clis: updatedSettings };

		const response = await apiRequest.call(this, 'POST', endpoint, body);
		console.log('API Response for setApSsids:', response);

		return formatResponse({
			success: true,
			message: `SSIDs updated for AP ${serialNumber}`,
			ssids: ssids,
			updatedSettings: updatedSettings,
		});
	} catch (error) {
		console.log('ERROR in setApSsids:', error);
		throw error;
	}
}

/**
 * Set AP Radio Profile (rf-zone)
 */
export async function setApRadioProfile(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
	try {
		let serialNumber = this.getNodeParameter('serialNumber', 0) as string;
		const profileName = this.getNodeParameter('profileName', 0) as string;

		if (!serialNumber || !profileName) {
			throw new Error('Serial number and radio profile name are required');
		}

		// Normalize serial number to uppercase
		serialNumber = normalizeSerial(serialNumber);

		console.log(`Setting Radio Profile "${profileName}" for AP with serial: ${serialNumber}`);

		// Get current settings
		const currentSettings = await getApSettings(this, serialNumber);

		// Format the rf-zone line with proper indentation
		const newRfZoneLine = `  rf-zone ${profileName}`;

		// Update settings with new radio profile
		const updatedSettings = updateApSetting(currentSettings, 'rf-zone', newRfZoneLine);

		// Update configuration
		const endpoint = `/configuration/v1/ap_settings_cli/${serialNumber}`;
		const body = { clis: updatedSettings };

		const response = await apiRequest.call(this, 'POST', endpoint, body);
		console.log('API Response for setApRadioProfile:', response);

		return formatResponse({
			success: true,
			message: `Radio profile updated to "${profileName}" for AP ${serialNumber}`,
			profileName: profileName,
			updatedSettings: updatedSettings,
		});
	} catch (error) {
		console.log('ERROR in setApRadioProfile:', error);
		throw error;
	}
}

/**
 * Combined operation to set both RF Zone and SSIDs in one request
 */
export async function setApRfZoneAndSsids(this: IExecuteFunctions): Promise<INodeExecutionData[]> {
	try {
		let serialNumber = this.getNodeParameter('serialNumber', 0) as string;
		const profileName = this.getNodeParameter('profileName', 0) as string;
		const ssids = this.getNodeParameter('ssids', 0) as string[];

		if (!serialNumber || !profileName || !ssids || ssids.length === 0) {
			throw new Error('Serial number, profile name, and at least one SSID are required');
		}

		// Normalize serial number to uppercase
		serialNumber = normalizeSerial(serialNumber);

		console.log(
			`Setting Radio Profile "${profileName}" and SSIDs for AP with serial: ${serialNumber}`,
		);

		// Get current settings
		const currentSettings = await getApSettings(this, serialNumber);

		// Format lines with proper indentation
		const newRfZoneLine = `  rf-zone ${profileName}`;
		const ssidString = ssids.join(',');
		const newZonenameLine = `  zonename "${ssidString}"`;

		// First update the rf-zone
		let intermediateSettings = updateApSetting(currentSettings, 'rf-zone', newRfZoneLine);

		// Then update the zonename
		let updatedSettings = updateApSetting(intermediateSettings, 'zonename', newZonenameLine);

		// Update configuration
		const endpoint = `/configuration/v1/ap_settings_cli/${serialNumber}`;
		const body = { clis: updatedSettings };

		const response = await apiRequest.call(this, 'POST', endpoint, body);
		console.log('API Response for setApRfZoneAndSsids:', response);

		return formatResponse({
			success: true,
			message: `Radio profile and SSIDs updated for AP ${serialNumber}`,
			profileName: profileName,
			ssids: ssids,
			updatedSettings: updatedSettings,
		});
	} catch (error) {
		console.log('ERROR in setApRfZoneAndSsids:', error);
		throw error;
	}
}
