import { LoggingService } from '#services/file-system/logService';
import Config from '#config';

const logger = new LoggingService();

// Q-05: Simplified OneSignal service — single modern-API path with legacy fallback when needed.
class OneSignalService {
	private static readonly MODERN_API_URL = 'https://api.onesignal.com/notifications?c=push';
	private static readonly LEGACY_API_URL = 'https://onesignal.com/api/v1/notifications';

	private static get appId() {
		return Config.oneSignal.appId.trim();
	}

	private static get apiKey() {
		return Config.oneSignal.apiKey.trim();
	}

	/**
	 * Send a push notification via OneSignal.
	 * Supports:
	 *  - `player_ids` — direct player ID targeting (legacy API)
	 *  - `userId` (external_id) — modern API with legacy fallback on 401/403
	 */
	static async sendNotification(params: {
		title?: string;
		content?: string;
		userId?: string;
		player_ids?: string[];
		headings?: { en?: string };
		contents?: { en?: string };
		data?: Record<string, any>;
	}): Promise<{ id?: string } | boolean> {
		if (!this.appId || !this.apiKey) {
			logger
				.logErrorAsync('OneSignal', new Error('Missing ONESIGNAL_APP_ID or ONESIGNAL_API_KEY'), null)
				.catch(() => {});
			return false;
		}

		// ── Path A: player_ids (legacy targeting) ──────────────────────────────
		if (params.player_ids && params.player_ids.length > 0) {
			try {
				const response = await fetch(this.LEGACY_API_URL, {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						Authorization: `Basic ${this.apiKey}`,
					},
					body: JSON.stringify({
						app_id: this.appId,
						include_player_ids: params.player_ids,
						headings: params.headings ?? { en: params.title ?? '' },
						contents: params.contents ?? { en: params.content ?? '' },
						data: params.data,
					}),
				});

				const body: any = await response.json().catch(() => null);
				if (!response.ok) {
					logger.logErrorAsync('OneSignal', new Error(`Send failed: ${response.status}`), body).catch(() => {});
					return false;
				}
				return body;
			} catch (error) {
				logger.logErrorAsync('OneSignal', error as Error, null).catch(() => {});
				return false;
			}
		}

		// ── Path B: external_id (modern API, fallback to legacy on auth errors) ─
		const normalizedUserId = typeof params.userId === 'string' ? params.userId.trim() : '';
		if (!normalizedUserId) {
			logger.logErrorAsync('OneSignal', new Error(`Invalid external_id: ${params.userId}`), null).catch(() => {});
			return false;
		}

		const heading = params.headings ?? { en: params.title ?? '' };
		const content = params.contents ?? { en: params.content ?? '' };

		try {
			// Try modern API first
			let response = await fetch(this.MODERN_API_URL, {
				method: 'POST',
				headers: {
					'Content-Type': 'application/json',
					Authorization: `Key ${this.apiKey}`,
				},
				body: JSON.stringify({
					app_id: this.appId,
					target_channel: 'push',
					headings: heading,
					contents: content,
					include_aliases: { external_id: [normalizedUserId] },
					web_push_topic: 'general',
					data: params.data,
				}),
			});

			// Fallback to legacy API if credentials are bound to old plan
			if (response.status === 401 || response.status === 403) {
				response = await fetch(this.LEGACY_API_URL, {
					method: 'POST',
					headers: {
						'Content-Type': 'application/json',
						Authorization: `Basic ${this.apiKey}`,
					},
					body: JSON.stringify({
						app_id: this.appId,
						headings: heading,
						contents: content,
						include_external_user_ids: [normalizedUserId],
						web_push_topic: 'general',
						data: params.data,
					}),
				});
			}

			const body: any = await response.json().catch(() => null);
			if (!response.ok) {
				logger.logErrorAsync('OneSignal', new Error(`Send failed: ${response.status}`), body).catch(() => {});
				return false;
			}

			if (!body?.id) {
				logger.logErrorAsync('OneSignal', new Error('Accepted but no message id returned'), body).catch(() => {});
				return false;
			}

			return body;
		} catch (error) {
			logger.logErrorAsync('OneSignal', error as Error, null).catch(() => {});
			return false;
		}
	}
}

export default OneSignalService;
