/**
 * Network Status Monitor
 * Monitor network connectivity to database server continuously
 * Auto-recovery when network becomes available
 */

const NetworkDiagnostics = require('./networkDiagnostics');
const EventEmitter = require('events');

class NetworkStatusMonitor extends EventEmitter {
	constructor(config, options = {}) {
		super();
		this.config = config;
		this.options = {
			checkInterval: options.checkInterval || 30000, // Check every 30 seconds
			timeout: options.timeout || 10000, // 10 second timeout per check
			successThreshold: options.successThreshold || 2, // Need 2 successful checks to mark as up
			failureThreshold: options.failureThreshold || 3, // Need 3 failed checks to mark as down
			enabled: options.enabled !== false, // Enabled by default
			...options
		};

		this.status = {
			isOnline: null, // null = unknown, true = online, false = offline
			lastCheck: null,
			lastSuccess: null,
			lastFailure: null,
			consecutiveSuccesses: 0,
			consecutiveFailures: 0,
			totalChecks: 0,
			totalSuccesses: 0,
			totalFailures: 0,
			currentError: null,
			networkDiagnostic: null
		};

		this.isMonitoring = false;
		this.monitorInterval = null;
		this.checkPromise = null;
	}

	/**
	 * Start monitoring network status
	 */
	start() {
		if (this.isMonitoring) {
			console.log('[NetworkStatusMonitor] Already monitoring');
			return;
		}

		if (!this.options.enabled) {
			console.log('[NetworkStatusMonitor] Monitoring disabled');
			return;
		}

		this.isMonitoring = true;
		console.log(`[NetworkStatusMonitor] Starting network status monitoring (check every ${this.options.checkInterval}ms)`);
		
		// Initial check
		this.check().catch(err => {
			console.error('[NetworkStatusMonitor] Initial check failed:', err.message);
		});

		// Periodic checks
		this.monitorInterval = setInterval(() => {
			if (!this.checkPromise) {
				this.check().catch(err => {
					console.error('[NetworkStatusMonitor] Periodic check failed:', err.message);
				});
			}
		}, this.options.checkInterval);
	}

	/**
	 * Stop monitoring network status
	 */
	stop() {
		if (!this.isMonitoring) {
			return;
		}

		this.isMonitoring = false;
		if (this.monitorInterval) {
			clearInterval(this.monitorInterval);
			this.monitorInterval = null;
		}
		console.log('[NetworkStatusMonitor] Stopped monitoring');
	}

	/**
	 * Perform network connectivity check
	 */
	async check() {
		if (this.checkPromise) {
			return this.checkPromise;
		}

		this.checkPromise = this._performCheck();
		const result = await this.checkPromise;
		this.checkPromise = null;
		return result;
	}

	async _performCheck() {
		const startTime = Date.now();
		this.status.lastCheck = new Date().toISOString();
		this.status.totalChecks++;

		try {
			const result = await NetworkDiagnostics.testTCPConnection(
				this.config.host,
				this.config.port,
				this.options.timeout
			);

			const duration = Date.now() - startTime;

			if (result.success) {
				this.status.consecutiveSuccesses++;
				this.status.consecutiveFailures = 0;
				this.status.totalSuccesses++;
				this.status.lastSuccess = new Date().toISOString();
				this.status.currentError = null;
				this.status.networkDiagnostic = null;

				// Mark as online if we have enough consecutive successes
				if (this.status.consecutiveSuccesses >= this.options.successThreshold) {
					if (this.status.isOnline !== true) {
						const wasOffline = this.status.isOnline === false;
						this.status.isOnline = true;
						console.log(`[NetworkStatusMonitor] Network is now ONLINE (${duration}ms)`);
						this.emit('online', {
							duration,
							consecutiveSuccesses: this.status.consecutiveSuccesses,
							wasOffline
						});
					}
				}

				return {
					success: true,
					duration,
					status: 'online',
					consecutiveSuccesses: this.status.consecutiveSuccesses
				};
			} else {
				this.status.consecutiveSuccesses = 0;
				this.status.consecutiveFailures++;
				this.status.totalFailures++;
				this.status.lastFailure = new Date().toISOString();
				this.status.currentError = result.error;
				this.status.networkDiagnostic = NetworkDiagnostics.getNetworkErrorInfo({
					code: result.error,
					message: result.message
				});

				// Mark as offline if we have enough consecutive failures
				if (this.status.consecutiveFailures >= this.options.failureThreshold) {
					if (this.status.isOnline !== false) {
						const wasOnline = this.status.isOnline === true;
						this.status.isOnline = false;
						console.error(`[NetworkStatusMonitor] Network is now OFFLINE: ${result.error} (${duration}ms)`);
						console.error(`[NetworkStatusMonitor] Error Type: ${this.status.networkDiagnostic.errorType}`);
						console.error(`[NetworkStatusMonitor] Suggestion: ${this.status.networkDiagnostic.suggestion}`);
						this.emit('offline', {
							error: result.error,
							errorType: this.status.networkDiagnostic.errorType,
							message: this.status.networkDiagnostic.userMessage,
							suggestion: this.status.networkDiagnostic.suggestion,
							duration,
							consecutiveFailures: this.status.consecutiveFailures,
							wasOnline
						});
					}
				}

				return {
					success: false,
					error: result.error,
					errorType: this.status.networkDiagnostic.errorType,
					message: this.status.networkDiagnostic.userMessage,
					suggestion: this.status.networkDiagnostic.suggestion,
					duration,
					status: 'offline',
					consecutiveFailures: this.status.consecutiveFailures
				};
			}
		} catch (error) {
			const duration = Date.now() - startTime;
			this.status.consecutiveSuccesses = 0;
			this.status.consecutiveFailures++;
			this.status.totalFailures++;
			this.status.lastFailure = new Date().toISOString();
			this.status.currentError = error.code || error.message;
			this.status.networkDiagnostic = NetworkDiagnostics.getNetworkErrorInfo(error);

			if (this.status.consecutiveFailures >= this.options.failureThreshold) {
				if (this.status.isOnline !== false) {
					const wasOnline = this.status.isOnline === true;
					this.status.isOnline = false;
					console.error(`[NetworkStatusMonitor] Network is now OFFLINE: ${error.message} (${duration}ms)`);
					this.emit('offline', {
						error: error.code || error.message,
						errorType: this.status.networkDiagnostic.errorType,
						message: this.status.networkDiagnostic.userMessage,
						suggestion: this.status.networkDiagnostic.suggestion,
						duration,
						consecutiveFailures: this.status.consecutiveFailures,
						wasOnline
					});
				}
			}

			return {
				success: false,
				error: error.code || error.message,
				errorType: this.status.networkDiagnostic.errorType,
				message: this.status.networkDiagnostic.userMessage,
				suggestion: this.status.networkDiagnostic.suggestion,
				duration,
				status: 'offline',
				consecutiveFailures: this.status.consecutiveFailures
			};
		}
	}

	/**
	 * Get current network status
	 */
	getStatus() {
		return {
			...this.status,
			isMonitoring: this.isMonitoring
		};
	}

	/**
	 * Check if network is currently online
	 */
	isOnline() {
		return this.status.isOnline === true;
	}

	/**
	 * Check if network is currently offline
	 */
	isOffline() {
		return this.status.isOnline === false;
	}

	/**
	 * Get network diagnostic information
	 */
	getDiagnostic() {
		return this.status.networkDiagnostic;
	}

	/**
	 * Force a check and wait for result
	 */
	async forceCheck() {
		return await this.check();
	}
}

module.exports = NetworkStatusMonitor;
