// 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 { Component, OnInit, NgZone } from '@angular/core';
import { InfiniteScrollCustomEvent } from '@ionic/angular';
import { ActivatedRoute } from '@angular/router';
import { CapacitorBarcodeScanner, CapacitorBarcodeScannerTypeHint } from '@capacitor/barcode-scanner';

import { ConfigService } from 'src/app/providers/config.service';
import { PlacesService } from 'src/app/providers/places.service';
import { GeolocationService } from 'src/app/providers/geolocation.service';
import { LayoutService } from 'src/app/providers/layout.service';
import { BizReviewsService } from 'src/app/providers/biz-reviews.service';
import { Review, ReviewStats } from 'src/models/biz-appointments/review.model';

/**
 * Turismo (ex tab "Luoghi" della bacheca): servizio pubblico, visibile a tutti.
 * Lista luoghi + mappa + audioguide + sotto-luoghi (miniature + popup).
 */
@Component({
	selector: 'app-turismo',
	templateUrl: './turismo.component.html',
	styleUrls: ['./turismo.component.scss'],
	standalone: false,
})
export class TurismoComponent implements OnInit {
	imageBaseURL?: string;
	cmp_id?: number;
	limitda!: number;
	pageelement?: number;
	urlPhotoPlace = '';
	urlAudio = '';
	cerca?: any;

	// LUOGHI
	lstLocations: any[] = [];
	filterLOC: any = {};
	placesHasMore = true;
	loadingPlaces = true;
	espanseIds = new Set<any>();

	// AUDIO modal
	audioModalOpen = false;
	audio: any;

	// SOTTO-LUOGO popup
	subModalOpen = false;
	selectedSub: any = null;

	// RECENSIONI luogo (solo utenti loggati; caricate al primo tap sulla riga)
	isLogged = false;
	reviewsOpen = new Set<number>();
	placeStats: Record<number, ReviewStats> = {};
	placeReviews: Record<number, Review[]> = {};
	stars = [1, 2, 3, 4, 5];

	// MAPPA
	mapCenter: google.maps.LatLngLiteral = { lat: 42.5, lng: 13.0 };
	mapZoom = 6;
	mapOptions: google.maps.MapOptions = {
		disableDefaultUI: true,
		zoomControl: true,
		gestureHandling: 'cooperative',
	};
	placeMarkers: { position: google.maps.LatLngLiteral; plc_id: number; title: string; options: google.maps.MarkerOptions }[] = [];
	myPosition?: google.maps.LatLngLiteral;
	myPositionOptions: google.maps.MarkerOptions = {
		icon: 'https://maps.google.com/mapfiles/ms/icons/blue-dot.png',
		title: 'La tua posizione',
		zIndex: 9999,
	};
	private geocoder?: google.maps.Geocoder;
	private geoCache = new Map<number, google.maps.LatLngLiteral>();
	private geoRetries = 0;

	constructor(private configService: ConfigService, private route: ActivatedRoute, private placesService: PlacesService, private ngZone: NgZone, private geo: GeolocationService, private layoutService: LayoutService, private reviewsService: BizReviewsService) {}

	placeSrcset(p: any): string {
		const u = this.urlPhotoPlace;
		const sm = p.plm_path_sm || p.plm_path_lg;
		const md = p.plm_path_md || p.plm_path_lg;
		const lg = p.plm_path_lg;
		return `${u}${sm} 400w, ${u}${md} 800w, ${u}${lg} 1280w`;
	}

	ngOnInit(): void {
		// cmp_id dalla rotta (/portale/:prt_id/company/:cmp_id/service/turismo), risalendo i parent.
		this.cmp_id = -1;
		let r: ActivatedRoute | null = this.route;
		while (r) {
			const pm = r.snapshot.paramMap;
			if (pm.get('cmp_id')) {
				this.cmp_id = +(pm.get('cmp_id') as string);
				break;
			}
			r = r.parent;
		}
		this.limitda = 1;
		this.pageelement = 20;
		this.imageBaseURL = this.configService.imageBaseURL;
		this.urlPhotoPlace = this.configService.placesImageUrl;
		this.urlAudio = this.configService.placesAudioUrl;
		this.isLogged = this.configService.isLogged();
		this.resetFilters();
	}

	ionViewWillEnter() {
		this.layoutService.setPageConfig({ title: '', showBack: false, showHeader: false, tab: 'turismo' });
		this.getListLOC();
	}

	ionViewWillLeave() {
		this.layoutService.setPageConfig({ showHeader: true });
	}

	resetFilters() {
		this.filterLOC.plc_cmp_id = this.cmp_id;
		this.filterLOC.pagina = this.limitda;
		this.filterLOC.righePagina = this.pageelement;
		this.filterLOC.plc_name = '';
		this.filterLOC.plc_city_code = '';
		this.getListLOC();
	}

	filterPlaces() {
		this.filterLOC.plc_name = this.cerca;
		this.resetPaging();
		this.getListLOC();
	}

	onSearchClear() {
		this.cerca = '';
		this.filterLOC.plc_name = '';
		this.resetPaging();
		this.getListLOC();
	}

	private resetPaging() {
		this.filterLOC.pagina = 1;
		this.placesHasMore = true;
	}

	SeeMore(id: any) {
		this.espanseIds.add(id);
	}

	SeeLess(id: any) {
		this.espanseIds.delete(id);
	}

	getListLOC(append = false) {
		if (!append) {
			this.lstLocations = [];
			this.loadingPlaces = true;
		}
		this.placesService.getListLocations(this.filterLOC).subscribe({
			next: (res) => {
				res = res || [];
				this.placesHasMore = res.length >= (this.pageelement ?? 20);
				this.lstLocations = append ? [...this.lstLocations, ...res] : res;
				this.buildPlaceMarkers(this.lstLocations);
				this.loadingPlaces = false;
			},
			error: () => {
				this.loadingPlaces = false;
			},
		});
	}

	// ── RECENSIONI luogo ─────────────────────────────────────
	toggleReviews(plc_id: number) {
		if (this.reviewsOpen.has(plc_id)) {
			this.reviewsOpen.delete(plc_id);
			return;
		}
		this.reviewsOpen.add(plc_id);
		if (!this.placeStats[plc_id]) this.loadPlaceReviews(plc_id);
	}

	loadPlaceReviews(plc_id: number) {
		// Una sola chiamata: lista + statistiche insieme
		this.reviewsService.getPlaceReviews(plc_id, 5, 0).subscribe({
			next: (res) => {
				this.placeReviews[plc_id] = res.list || [];
				this.placeStats[plc_id] = res.stats;
			},
		});
	}

	// SOTTO-LUOGO popup (nome + descrizione + immagine + audioguida)
	openSub(sub: any) {
		this.selectedSub = sub;
		this.subModalOpen = true;
	}

	private buildPlaceMarkers(places: any[]) {
		const g = (window as any).google;
		if (!g?.maps) {
			if (this.geoRetries++ < 10) {
				setTimeout(() => this.buildPlaceMarkers(places), 600);
			}
			return;
		}
		this.geoRetries = 0;
		this.geocoder = this.geocoder || new g.maps.Geocoder();
		this.placeMarkers = [];

		places.forEach((plc) => {
			const img = plc.photo?.length ? this.urlPhotoPlace + plc.photo[0].plm_path_sm : null;
			const addMarker = (position: google.maps.LatLngLiteral) => {
				this.ngZone.run(() => {
					this.placeMarkers = [
						...this.placeMarkers,
						{
							position,
							plc_id: plc.plc_id,
							title: plc.plc_name,
							options: img ? { icon: { url: img, scaledSize: new g.maps.Size(46, 46) } } : {},
						},
					];
					if (this.placeMarkers.length === 1) {
						this.mapCenter = position;
						this.mapZoom = 13;
					}
				});
			};

			const lat = plc.plc_lat ?? plc.plc_latitude ?? plc.plc_lat_dec;
			const lng = plc.plc_lng ?? plc.plc_longitude ?? plc.plc_lon ?? plc.plc_lng_dec;
			if (lat != null && lng != null && !isNaN(+lat) && !isNaN(+lng)) {
				addMarker({ lat: +lat, lng: +lng });
				return;
			}

			const cached = this.geoCache.get(plc.plc_id);
			if (cached) {
				addMarker(cached);
				return;
			}

			const address = `${plc.plc_address || ''} ${plc.plc_number || ''}, ${plc.plc_city || ''} ${plc.plc_codiceprovincia ? '(' + plc.plc_codiceprovincia + ')' : ''}`.trim();
			if (!address || address === ',') return;

			this.geocoder!.geocode({ address }, (results: any, status: any) => {
				if (status === 'OK' && results && results[0]) {
					const loc = results[0].geometry.location;
					const position = { lat: loc.lat(), lng: loc.lng() };
					this.geoCache.set(plc.plc_id, position);
					addMarker(position);
				}
			});
		});
	}

	onMarkerPlaceClick(plc_id: number) {
		const el = document.getElementById('place-' + plc_id);
		if (el) {
			el.scrollIntoView({ behavior: 'smooth', block: 'start' });
			this.espanseIds.add(plc_id);
		}
	}

	scrollToMap() {
		document.getElementById('places-top')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
	}

	async centerOnMyPosition() {
		try {
			const pos = await this.geo.requestPosition();
			this.ngZone.run(() => {
				this.myPosition = { lat: pos.latitude, lng: pos.longitude };
				this.mapCenter = this.myPosition;
				this.mapZoom = 14;
			});
		} catch (e) {
			this.configService.presentToastError('Impossibile ottenere la posizione. Controlla i permessi di localizzazione.');
		}
	}

	async scanQrCode() {
		try {
			const result = await CapacitorBarcodeScanner.scanBarcode({
				hint: CapacitorBarcodeScannerTypeHint.QR_CODE,
			});
			if (!result.ScanResult) return;

			let scan = JSON.parse(result.ScanResult);
			if (scan.type == 'audioguide') {
				this.placesService.getAudiobyUUID(scan.uuid).subscribe({
					next: (res) => {
						this.audio = res;
						this.audioModalOpen = true;
					},
					error: (err) => this.configService.presentToastError(err),
				});
			}
		} catch (e: any) {
			this.configService.presentToastError('Impossibile avviare lo scanner: ' + e?.message);
		}
	}

	openAudio(uuid: string) {
		this.placesService.getAudiobyUUID(uuid).subscribe({
			next: (res) => {
				this.audio = res;
				this.audioModalOpen = true;
			},
			error: (err) => this.configService.presentToastError(err),
		});
	}

	onIonInfinite(ev: InfiniteScrollCustomEvent) {
		this.filterLOC.pagina++;
		this.getListLOC(true);
		setTimeout(() => ev.target.complete(), 800);
	}
}
