// Questo file fa parte di MyTown.
// MyTown è software libero: puoi ridistribuirlo e/o modificarlo secondo
// i termini della GNU Affero General Public License come pubblicata dalla
// Free Software Foundation, versione 3.
// Distribuito senza ALCUNA GARANZIA; vedi la GNU AGPL v3 per i dettagli.
// Copyright (C) Kondor Consulting & Services S.r.l.
// SPDX-License-Identifier: AGPL-3.0-or-later

import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Capacitor } from '@capacitor/core';
import { PushNotifications, Token, PushNotificationSchema, ActionPerformed } from '@capacitor/push-notifications';
import { Device } from '@capacitor/device';
import { Browser } from '@capacitor/browser';
import { AlertController, Platform } from '@ionic/angular';
import { ConfigService } from './config.service';
import { Subject } from 'rxjs';

const PUSH_DISABLED_KEY = 'kcs_push_disabled';

export type PushPermissionStatus = 'granted' | 'denied' | 'prompt' | 'unavailable';

@Injectable({ providedIn: 'root' })
export class PushService {
	private currentToken: string | null = null;
	private initialized = false;

	notificationReceived$ = new Subject<PushNotificationSchema>();
	notificationAction$ = new Subject<ActionPerformed>();

	constructor(
		private http: HttpClient,
		private config: ConfigService,
		private platform: Platform,
		private alertCtrl: AlertController,
	) {}

	async initialize(): Promise<void> {
		if (this.initialized) return;
		if (Capacitor.getPlatform() === 'web') return;

		// Se l'utente ha disabilitato in-app, non registrare
		if (this.isDisabledLocally()) return;

		try {
			const permResult = await PushNotifications.requestPermissions();
			if (permResult.receive !== 'granted') {
				console.warn('Push notification permission not granted');
				return;
			}

			await PushNotifications.register();

			PushNotifications.addListener('registration', (token: Token) => {
				console.log('FCM token received:', token.value.substring(0, 20) + '...');
				this.currentToken = token.value;
				this.subscribeToBackend();
			});

			PushNotifications.addListener('registrationError', (error: any) => {
				console.error('Push registration error:', error);
			});

			PushNotifications.addListener('pushNotificationReceived', (notification: PushNotificationSchema) => {
				console.log('Push received in foreground:', notification);
				this.notificationReceived$.next(notification);
			});

			PushNotifications.addListener('pushNotificationActionPerformed', (action: ActionPerformed) => {
				console.log('Push notification action:', action);
				this.notificationAction$.next(action);
			});

			this.initialized = true;
		} catch (error) {
			console.error('Push initialization error:', error);
		}
	}

	/** Controlla il permesso di sistema (non in-app). */
	async checkPermissionStatus(): Promise<PushPermissionStatus> {
		if (Capacitor.getPlatform() === 'web') return 'unavailable';
		try {
			const result = await PushNotifications.checkPermissions();
			switch (result.receive) {
				case 'granted':
					return 'granted';
				case 'denied':
					return 'denied';
				default:
					return 'prompt';
			}
		} catch {
			return 'unavailable';
		}
	}

	/** Richiede il permesso di sistema (mostra il dialog nativo). */
	async requestSystemPermission(): Promise<boolean> {
		if (Capacitor.getPlatform() === 'web') return false;
		try {
			const result = await PushNotifications.requestPermissions();
			if (result.receive === 'granted') {
				this.setDisabledLocally(false);
				await PushNotifications.register();
				return true;
			}
			return false;
		} catch {
			return false;
		}
	}

	/** Apre le impostazioni di sistema per le notifiche.
	 *  Su iOS usa l'URL scheme; su Android mostra istruzioni. */
	async openSystemNotificationSettings(): Promise<void> {
		if (this.platform.is('ios')) {
			await Browser.open({ url: 'app-settings:' });
		} else {
			await this.showOpenSettingsGuide();
		}
	}

	private async showOpenSettingsGuide(): Promise<void> {
		const isAndroid = this.platform.is('android');
		const steps = isAndroid ? 'Impostazioni → App → DataSmart → Notifiche → Consenti notifiche' : 'Impostazioni → Notifiche → DataSmart → Abilita notifiche';

		const alert = await this.alertCtrl.create({
			header: 'Abilita notifiche',
			message: `Le notifiche push sono disabilitate nel sistema.<br><br>Segui questi passaggi:<br><strong>${steps}</strong>`,
			buttons: ['Chiudi'],
			cssClass: 'push-settings-alert',
		});
		await alert.present();
	}

	/** Flag locale: l'utente ha disabilitato le push dall'app. */
	isDisabledLocally(): boolean {
		return localStorage.getItem(PUSH_DISABLED_KEY) === 'true';
	}

	private setDisabledLocally(disabled: boolean): void {
		localStorage.setItem(PUSH_DISABLED_KEY, disabled ? 'true' : 'false');
	}

	/** Disabilita le push in-app e cancella la subscription dal backend. */
	async disablePushLocally(): Promise<void> {
		this.setDisabledLocally(true);
		this.initialized = false;
		this.subscribeAttempted = false;
		await this.unsubscribeFromBackend();
	}

	/** Abilita le push in-app e registra la subscription sul backend. */
	async enablePushLocally(): Promise<void> {
		this.setDisabledLocally(false);
		await this.initialize();
	}

	getToken(): string | null {
		return this.currentToken;
	}

	private subscribeAttempted = false;

	async subscribeToBackend(): Promise<void> {
		if (!this.currentToken) return;
		if (!this.config.isAuthenticated()) return;
		if (this.subscribeAttempted) return;
		this.subscribeAttempted = true;

		try {
			const device = await Device.getInfo();
			const body = {
				ps_token: this.currentToken,
				ps_platform: device.platform,
				ps_language: 'it',
				ps_model: device.model,
			};
			this.http.post(this.config.serviceUrl_PortalManager + 'push/subscribe', body).subscribe({
				next: () => console.log('Push subscription registered on backend'),
				error: (err: any) => {
					// Silenzia il log: il backend ritorna 204 in caso di utente non trovato,
					// ma per qualunque altro errore non vogliamo spammare la console né ritentare.
					console.warn('Push subscribe skipped:', err?.status || err);
				},
			});
		} catch (error) {
			console.warn('Push subscribe skipped (device info):', error);
		}
	}

	async unsubscribeFromBackend(): Promise<void> {
		if (!this.currentToken) return;

		try {
			this.http.post(this.config.serviceUrl_PortalManager + 'push/unsubscribe', { token: this.currentToken }).subscribe({
				next: () => console.log('Push subscription removed from backend'),
				error: (err: any) => console.error('Push unsubscribe error:', err),
			});
		} catch (error) {
			console.error('Error unsubscribing push token:', error);
		}
	}
}
