/**
 * API Client dengan ISP Blocking Mitigation
 * Helper untuk frontend SAPPS
 *
 * Features:
 * - Automatic retry dengan exponential backoff
 * - Multiple endpoint fallback
 * - Connection quality monitoring
 * - Offline detection
 */

class ResilientAPIClient {
	constructor(config = {}) {
		this.primaryEndpoint = config.primaryEndpoint || "https://sapps-api.sapharma.co.id";
		this.fallbackEndpoints = config.fallbackEndpoints || [];
		this.maxRetries = config.maxRetries || 3;
		this.timeout = config.timeout || 30000; // 30 seconds
		this.onConnectionQualityChange = config.onConnectionQualityChange || (() => {});
		this.onOffline = config.onOffline || (() => {});
		this.onOnline = config.onOnline || (() => {});

		// Connection monitoring
		this.lastLatency = null;
		this.connectionQuality = "unknown";

		// Setup offline/online listeners
		this.setupNetworkListeners();
	}

	/**
	 * Setup network event listeners
	 */
	setupNetworkListeners() {
		if (typeof window !== "undefined") {
			window.addEventListener("online", () => {
				console.log("✅ Connection restored");
				this.onOnline();
			});

			window.addEventListener("offline", () => {
				console.warn("⚠️ Connection lost");
				this.onOffline();
			});
		}
	}

	/**
	 * Main fetch method dengan retry dan fallback
	 */
	async fetch(path, options = {}) {
		const endpoints = [this.primaryEndpoint, ...this.fallbackEndpoints];

		let lastError = null;

		// Try each endpoint
		for (const endpoint of endpoints) {
			try {
				const result = await this.fetchWithRetry(`${endpoint}${path}`, options);
				return result;
			} catch (error) {
				console.warn(`Endpoint ${endpoint} failed:`, error.message);
				lastError = error;
				// Continue to next endpoint
			}
		}

		// All endpoints failed
		throw new Error(`All endpoints failed. Last error: ${lastError?.message}`);
	}

	/**
	 * Fetch dengan retry logic
	 */
	async fetchWithRetry(url, options = {}, retryCount = 0) {
		try {
			const controller = new AbortController();
			const timeoutId = setTimeout(() => controller.abort(), this.timeout);

			const startTime = performance.now();

			const response = await fetch(url, {
				...options,
				signal: controller.signal,
			});

			clearTimeout(timeoutId);

			// Update latency
			this.lastLatency = performance.now() - startTime;
			this.updateConnectionQuality(this.lastLatency);

			// Check if response is ok
			if (!response.ok) {
				// Check for retry-after header
				const retryAfter = response.headers.get("X-Retry-After");

				if (retryAfter && retryCount < this.maxRetries) {
					console.log(`Retrying after ${retryAfter} seconds...`);
					await this.sleep(parseInt(retryAfter) * 1000);
					return this.fetchWithRetry(url, options, retryCount + 1);
				}

				// Check for specific status codes that warrant retry
				if ([408, 429, 500, 502, 503, 504].includes(response.status) && retryCount < this.maxRetries) {
					const backoffTime = this.calculateBackoff(retryCount);
					console.log(`Server error ${response.status}. Retrying in ${backoffTime}ms...`);
					await this.sleep(backoffTime);
					return this.fetchWithRetry(url, options, retryCount + 1);
				}

				throw new Error(`HTTP ${response.status}: ${response.statusText}`);
			}

			return response;
		} catch (error) {
			// Retry on network errors
			if (retryCount < this.maxRetries && this.isRetryableError(error)) {
				const backoffTime = this.calculateBackoff(retryCount);
				console.log(`Network error: ${error.message}. Retrying in ${backoffTime}ms... (${retryCount + 1}/${this.maxRetries})`);
				await this.sleep(backoffTime);
				return this.fetchWithRetry(url, options, retryCount + 1);
			}

			throw error;
		}
	}

	/**
	 * Check if error is retryable
	 */
	isRetryableError(error) {
		return (
			error.name === "AbortError" ||
			error.name === "TypeError" ||
			error.message.includes("fetch") ||
			error.message.includes("network") ||
			error.message.includes("timeout")
		);
	}

	/**
	 * Calculate exponential backoff
	 */
	calculateBackoff(retryCount) {
		// Exponential backoff: 1s, 2s, 4s
		return Math.min(1000 * Math.pow(2, retryCount), 10000);
	}

	/**
	 * Sleep helper
	 */
	sleep(ms) {
		return new Promise((resolve) => setTimeout(resolve, ms));
	}

	/**
	 * Update connection quality based on latency
	 */
	updateConnectionQuality(latency) {
		let quality = "excellent";

		if (latency > 3000) {
			quality = "poor";
		} else if (latency > 1000) {
			quality = "fair";
		} else if (latency > 500) {
			quality = "good";
		}

		if (quality !== this.connectionQuality) {
			this.connectionQuality = quality;
			this.onConnectionQualityChange(quality, latency);
		}
	}

	/**
	 * Get connection quality
	 */
	getConnectionQuality() {
		return {
			quality: this.connectionQuality,
			latency: this.lastLatency,
		};
	}

	/**
	 * Test connection to server
	 */
	async testConnection() {
		try {
			const startTime = performance.now();
			const response = await this.fetch("/ping");
			const data = await response.json();
			const latency = performance.now() - startTime;

			return {
				success: true,
				latency,
				data,
			};
		} catch (error) {
			return {
				success: false,
				error: error.message,
			};
		}
	}

	/**
	 * Get server health
	 */
	async getHealth() {
		const response = await this.fetch("/health");
		return response.json();
	}

	/**
	 * Get connection diagnostics
	 */
	async getDiagnostics() {
		const response = await this.fetch("/diagnostics");
		return response.json();
	}

	// ============ Convenience Methods ============

	/**
	 * GET request
	 */
	async get(path, options = {}) {
		const response = await this.fetch(path, {
			...options,
			method: "GET",
		});
		return response.json();
	}

	/**
	 * POST request
	 */
	async post(path, data, options = {}) {
		const response = await this.fetch(path, {
			...options,
			method: "POST",
			headers: {
				"Content-Type": "application/json",
				...options.headers,
			},
			body: JSON.stringify(data),
		});
		return response.json();
	}

	/**
	 * PUT request
	 */
	async put(path, data, options = {}) {
		const response = await this.fetch(path, {
			...options,
			method: "PUT",
			headers: {
				"Content-Type": "application/json",
				...options.headers,
			},
			body: JSON.stringify(data),
		});
		return response.json();
	}

	/**
	 * DELETE request
	 */
	async delete(path, options = {}) {
		const response = await this.fetch(path, {
			...options,
			method: "DELETE",
		});
		return response.json();
	}
}

// ============ Usage Example ============
/*

// Initialize client
const apiClient = new ResilientAPIClient({
  primaryEndpoint: 'https://sapps-api.sapharma.co.id',
  fallbackEndpoints: [
    'https://sapps-api-backup.sapharma.co.id',
    'https://api.sapps.sapharma.co.id'
  ],
  maxRetries: 3,
  timeout: 30000,
  onConnectionQualityChange: (quality, latency) => {
    console.log(`Connection quality: ${quality} (${latency}ms)`);
    // Update UI indicator
  },
  onOffline: () => {
    console.log('App is offline');
    // Show offline message
  },
  onOnline: () => {
    console.log('App is back online');
    // Hide offline message, retry failed requests
  }
});

// Test connection
const testResult = await apiClient.testConnection();
if (testResult.success) {
  console.log('Connected! Latency:', testResult.latency);
} else {
  console.error('Connection failed:', testResult.error);
}

// Make API calls
try {
  const users = await apiClient.get('/sapps/users', {
    headers: {
      'Authorization': 'Bearer YOUR_TOKEN'
    }
  });
  console.log('Users:', users);
} catch (error) {
  console.error('Failed to fetch users:', error);
}

// Check connection quality
const { quality, latency } = apiClient.getConnectionQuality();
console.log(`Connection: ${quality} (${latency}ms)`);

*/

export default ResilientAPIClient;
