// 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 { Capacitor } from '@capacitor/core';
import { CapacitorNfc, NfcEvent, PluginListenerHandle } from '@capgo/capacitor-nfc';

/**
 * Servizio di Riscossione lato manager — Step 2 del piano payment integration.
 *
 * "Riscossione simbolica" basata su NFC tap detection:
 *   1. Manager apre il modale "Avvicina la carta…"
 *   2. Il telefono attiva l'NFC reader (CapacitorNfc.startScanning)
 *   3. Su nfcEvent → resolve con tag rilevato → l'orchestratore esterno chiama
 *      pay/config + pay/save con type_code='CASH'
 *      (è un pagamento contanti firmato col gesto NFC, NON un vero addebito gateway)
 *   3a. Step 3 futuro: integrazione SumUp/Stripe Terminal per addebito reale.
 */

export type RiscossioneResult =
	| { kind: 'ok'; tagId: string | null; tagPayload: string | null }
	| { kind: 'cancelled' }
	| { kind: 'unsupported' }
	| { kind: 'disabled' }
	| { kind: 'error'; message: string };

@Injectable({ providedIn: 'root' })
export class RiscossioneService {

	private _abortController: AbortController | null = null;
	private _listenerHandle: PluginListenerHandle | null = null;
	private _scanning = false;

	/** Vero se il device ha hardware NFC (a prescindere se attivo) */
	async isAvailable(): Promise<boolean> {
		if (Capacitor.getPlatform() === 'web') return false;
		try {
			const r = await CapacitorNfc.isSupported();
			return !!r?.supported;
		} catch {
			return false;
		}
	}

	/** Stato dell'adapter NFC: NFC_OK / NO_NFC / NFC_DISABLED / NDEF_PUSH_DISABLED */
	async getStatus(): Promise<string> {
		try {
			const r = await CapacitorNfc.getStatus();
			return r?.status || 'NO_NFC';
		} catch {
			return 'NO_NFC';
		}
	}

	/**
	 * Avvia il listener NFC. Risolve appena viene rilevato il primo tag,
	 * oppure ritorna `cancelled` se viene chiamato `cancel()`.
	 */
	startListening(): Promise<RiscossioneResult> {
		return new Promise<RiscossioneResult>(async (resolve) => {
			if (Capacitor.getPlatform() === 'web') {
				resolve({ kind: 'unsupported' });
				return;
			}
			if (!(await this.isAvailable())) {
				resolve({ kind: 'unsupported' });
				return;
			}
			const status = await this.getStatus();
			if (status === 'NFC_DISABLED') {
				resolve({ kind: 'disabled' });
				return;
			}

			this._abortController = new AbortController();
			const signal = this._abortController.signal;
			let resolved = false;

			const cleanup = async () => {
				if (this._listenerHandle) {
					try { await this._listenerHandle.remove(); } catch {}
					this._listenerHandle = null;
				}
				if (this._scanning) {
					try { await CapacitorNfc.stopScanning(); } catch {}
					this._scanning = false;
				}
			};

			signal.addEventListener('abort', async () => {
				if (resolved) return;
				resolved = true;
				await cleanup();
				resolve({ kind: 'cancelled' });
			});

			try {
				// Listener su qualunque tag (NDEF, generic, ecc.)
				this._listenerHandle = await CapacitorNfc.addListener('nfcEvent', (event: NfcEvent) => {
					if (resolved) return;
					resolved = true;
					const tag = event?.tag;
					const tagId = tag?.id ? this._bytesToHex(tag.id) : null;
					let tagPayload: string | null = null;
					const rec = tag?.ndefMessage?.[0];
					if (rec?.payload?.length) {
						try { tagPayload = String.fromCharCode(...rec.payload); } catch {}
					}
					cleanup().finally(() => resolve({ kind: 'ok', tagId, tagPayload }));
				});

				await CapacitorNfc.startScanning({
					invalidateAfterFirstRead: true,
					alertMessage: 'Avvicina la carta o un tag NFC al dispositivo',
				});
				this._scanning = true;
			} catch (e: any) {
				if (!resolved) {
					resolved = true;
					await cleanup();
					resolve({ kind: 'error', message: e?.message || 'NFC error' });
				}
			}
		});
	}

	/** Annulla l'attesa di tap (chiude il modale, ecc.) */
	cancel(): void {
		if (this._abortController) {
			this._abortController.abort();
			this._abortController = null;
		}
	}

	/** Cleanup finale (chiamare in ngOnDestroy se la pagina chiude) */
	async dispose(): Promise<void> {
		this.cancel();
		if (this._listenerHandle) {
			try { await this._listenerHandle.remove(); } catch {}
			this._listenerHandle = null;
		}
		if (this._scanning) {
			try { await CapacitorNfc.stopScanning(); } catch {}
			this._scanning = false;
		}
	}

	private _bytesToHex(bytes: number[]): string {
		return bytes.map(b => (b & 0xff).toString(16).padStart(2, '0')).join(':').toUpperCase();
	}
}
