// 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 } from '@angular/core';
import { ActivatedRoute, Router } from '@angular/router';
import { HttpClient } from '@angular/common/http';
import { AlertController } from '@ionic/angular';
import { ConfigService } from '../../../providers/config.service';
import { LayoutService } from '../../../providers/layout.service';
import { FileDownloadService } from '../../../providers/fileDownload.service';
import { AssembleeService } from '../../../providers/assemblee.service';
import { FunctionService } from '../../../providers/function.service';
import { Assemblea, AssembleaPartecipante, ConvocazioneLettera, MILLESIMI_TOTALI } from '../../../models/assemblea.model';

@Component({
	selector: 'app-assemblea-detail',
	templateUrl: './assemblea-detail.page.html',
	styleUrls: ['./assemblea-detail.page.scss'],
	standalone: false,
})
export class AssembleaDetailPage {
	cmp_id = 0;
	prt_id = 0;
	asm_id = 0;

	// azioni di gestione pilotate dalla funzione di modulo (ruolo); isCondomino = vista sola lettura
	moduleName = 'Assemblee';
	canManage = false;
	isCondomino = false;
	myCstId = 0;
	private myCstLoaded = false;
	private ensuringFolder = false;

	asm: Assemblea | null = null;
	partecipanti: AssembleaPartecipante[] = [];
	convocazioni: ConvocazioneLettera[] = [];
	verbali: any[] = [];
	loading = false;
	uploadingVerbale = false;

	readonly MILLESIMI_TOTALI = MILLESIMI_TOTALI;

	constructor(
		private route: ActivatedRoute,
		private router: Router,
		private http: HttpClient,
		private config: ConfigService,
		public layout: LayoutService,
		private fileDownload: FileDownloadService,
		private alertCtrl: AlertController,
		private service: AssembleeService,
		private funService: FunctionService,
	) {}

	ionViewWillEnter() {
		this.resolveIds();
		this.layout.setPageConfig({ title: 'Assemblea', showBack: true, backButtonHref: `/portale/${this.prt_id}/company/${this.cmp_id}/service/assemblee/list` });
		// permessi via funzioni di modulo; getMyCustomer resta solo per filtrare la partecipazione del condomino
		this.funService.funzionibyuser(this.moduleName).subscribe((res: any[]) => {
			const funcs = (res || []).map((f) => f.mdfu_function);
			this.canManage = funcs.includes('add') || funcs.includes('modifica') || funcs.includes('delete');
			this.isCondomino = !this.canManage;
			this.service.getMyCustomer(this.cmp_id).subscribe((cst) => {
				this.myCstId = cst || 0;
				this.myCstLoaded = true;
				this.ensureFolderIfNeeded();
			});
		});
		this.load();
	}

	private resolveIds() {
		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);
			if (pm.get('prt_id')) this.prt_id = +(pm.get('prt_id') as string);
			if (pm.get('id')) this.asm_id = +(pm.get('id') as string);
			r = r.parent;
		}
	}

	load(ev?: any) {
		this.loading = true;
		this.service.getAssemblea(this.asm_id).subscribe({
			next: (a) => {
				this.asm = a;
				this.loading = false;
				ev?.target?.complete();
				this.verbali = [];
				if (a?.asm_folder_id) this.service.listVerbali(a.asm_folder_id, this.cmp_id).subscribe((v) => (this.verbali = v || []));
				this.ensureFolderIfNeeded();
			},
			error: () => {
				this.config.presentToastError('Errore nel caricamento dell’assemblea');
				this.loading = false;
				ev?.target?.complete();
			},
		});
		this.service.getPartecipanti(this.asm_id).subscribe((p) => (this.partecipanti = p || []));
		this.service.listConvocazioni(this.asm_id).subscribe((c) => (this.convocazioni = c || []));
	}

	// Assemblee create senza cartella documentale: il gestore che apre il dettaglio la rigenera (come il web)
	private ensureFolderIfNeeded() {
		if (!this.asm || !this.myCstLoaded || this.ensuringFolder) return;
		if (this.asm.asm_folder_id || this.isCondomino) return; // ha già la cartella, o è un condomino (sola lettura)
		this.ensuringFolder = true;
		const asmRef = this.asm;
		this.service.ensureAssembleaFolder(this.cmp_id, asmRef.asm_id, asmRef.asm_title).subscribe({
			next: (folderId) => {
				this.ensuringFolder = false;
				if (folderId > 0) {
					asmRef.asm_folder_id = folderId;
					this.service.listVerbali(folderId, this.cmp_id).subscribe((v) => (this.verbali = v || []));
				}
			},
			error: () => (this.ensuringFolder = false),
		});
	}

	// ─── ordine del giorno come righe ─────────────────────────────
	get odgRighe(): string[] {
		return (this.asm?.asm_odg || '')
			.split('\n')
			.map((s) => s.trim())
			.filter((s) => s.length > 0);
	}

	// ─── stato / tipo ─────────────────────────────────────────────
	get statusLabel(): string {
		const s = this.asm?.asm_status;
		if (s === 'annullata') return 'Annullata';
		if (s === 'conclusa') return 'Conclusa';
		return 'Programmata';
	}
	get statusColor(): string {
		const s = this.asm?.asm_status;
		if (s === 'annullata') return 'danger';
		if (s === 'conclusa') return 'success';
		return 'warning';
	}
	get tipoLabel(): string {
		return this.asm?.asm_type === 'straordinaria' ? 'Straordinaria' : 'Ordinaria';
	}
	get isProgrammata(): boolean {
		return this.asm?.asm_status === 'programmata';
	}

	// ─── quorum (art. 1136 c.c.) ──────────────────────────────────
	get showQuorum(): boolean {
		return this.asm?.asm_quorum === true;
	}
	get numPresenti(): number {
		return this.partecipanti.filter((p) => p.asp_presente === true).length;
	}
	get millesimiPresenti(): number {
		return Math.round(this.partecipanti.filter((p) => p.asp_presente === true).reduce((s, p) => s + Number(p.cst_millesimi || 0), 0) * 100) / 100;
	}
	get quorumPrima(): boolean {
		return this.millesimiPresenti >= (MILLESIMI_TOTALI * 2) / 3 && this.numPresenti > this.partecipanti.length / 2;
	}
	get quorumSeconda(): boolean {
		return this.millesimiPresenti >= MILLESIMI_TOTALI / 3 && this.numPresenti >= this.partecipanti.length / 3;
	}
	get millesimiPct(): number {
		return Math.min(100, Math.round((this.millesimiPresenti / MILLESIMI_TOTALI) * 100));
	}

	// ─── RSVP ─────────────────────────────────────────────────────
	canEditRsvp(p: AssembleaPartecipante): boolean {
		// conclusa/annullata: nessuno modifica le presenze (né condomino né gestore)
		if (!this.isProgrammata) return false;
		// condomino: solo la propria riga; gestore: tutte
		if (this.isCondomino) return p.asp_cst_id === this.myCstId;
		return true;
	}

	setRsvp(p: AssembleaPartecipante, presente: boolean) {
		if (!this.canEditRsvp(p)) return;
		const payload: AssembleaPartecipante = { ...p, asp_presente: presente };
		this.service.updateRsvp(payload).subscribe({
			next: () => {
				p.asp_presente = presente;
				this.config.presentToastSuccess('Presenza aggiornata');
			},
			error: () => this.config.presentToastError('Errore aggiornamento presenza'),
		});
	}

	presenzaLabel(p: AssembleaPartecipante): string {
		if (p.asp_presente === true) return 'Presente';
		if (p.asp_presente === false) return 'Assente';
		return 'In attesa';
	}
	presenzaColor(p: AssembleaPartecipante): string {
		if (p.asp_presente === true) return 'success';
		if (p.asp_presente === false) return 'danger';
		return 'medium';
	}

	get isMioPartecipante() {
		return (p: AssembleaPartecipante) => this.isCondomino && p.asp_cst_id === this.myCstId;
	}

	// ─── azioni gestore ───────────────────────────────────────────
	modifica() {
		this.router.navigate([`/portale/${this.prt_id}/company/${this.cmp_id}/service/assemblee/edit`, this.asm_id]);
	}

	async concludi() {
		// se non è ancora stato caricato un verbale, ricordalo prima di concludere
		const senzaVerbale = this.verbali.length === 0;
		const al = await this.alertCtrl.create({
			header: senzaVerbale ? 'Verbale mancante' : 'Concludi assemblea',
			message: senzaVerbale
				? 'Non risulta caricato il verbale di questa assemblea. Di norma il verbale va caricato prima di concludere. Concludere comunque?'
				: 'Contrassegnare questa assemblea come conclusa?',
			buttons: [
				{ text: 'Annulla', role: 'cancel' },
				{
					text: senzaVerbale ? 'Concludi comunque' : 'Concludi',
					handler: () => {
						this.service.setStatus(this.asm_id, 'conclusa').subscribe({
							next: () => {
								this.config.presentToastSuccess('Assemblea conclusa');
								this.load();
							},
							error: () => this.config.presentToastError('Errore'),
						});
					},
				},
			],
		});
		await al.present();
	}

	async annulla() {
		const al = await this.alertCtrl.create({
			header: 'Annulla assemblea',
			message: 'Annullare questa assemblea? I condòmini verranno informati.',
			buttons: [
				{ text: 'No', role: 'cancel' },
				{
					text: 'Annulla assemblea',
					role: 'destructive',
					handler: () => {
						this.service.setStatus(this.asm_id, 'annullata').subscribe({
							next: () => {
								this.config.presentToastSuccess('Assemblea annullata');
								this.load();
							},
							error: () => this.config.presentToastError('Errore'),
						});
					},
				},
			],
		});
		await al.present();
	}

	generaConvocazioni() {
		this.service.generaConvocazioni(this.asm_id).subscribe({
			next: (n) => {
				this.config.presentToastSuccess((n || 0) + ' lettere generate');
				this.service.listConvocazioni(this.asm_id).subscribe((c) => (this.convocazioni = c || []));
			},
			error: () => this.config.presentToastError('Errore generazione lettere'),
		});
	}

	// ─── download file documentale (file_dwn_zip → temp → apri) — lettere e verbali ─
	scaricaFile(drfl_id: number, filename?: string) {
		if (!drfl_id) return;
		const payload = { lst_folder: [], lst_file: [{ id: drfl_id, type: 'D' }] };
		this.http.post<{ res: string }>(`${this.config.serviceUrl_Documentary}file/file_dwn_zip`, payload).subscribe({
			next: (data) => {
				if (data && data.res) {
					const url = this.config.imageBaseURL + '/temp/' + data.res;
					this.fileDownload.downloadAndOpenFile(url, filename || data.res);
				}
			},
			error: () => this.config.presentToastError('Errore download del file'),
		});
	}

	verbaleName(v: any): string {
		return v?.drfl_name || v?.drfl_filename || v?.name || v?.nameView || '(documento)';
	}

	verbaleId(v: any): number {
		return v?.drfl_id ?? v?.id ?? v?.fileId ?? 0;
	}

	// ─── upload verbale (gestore) — stesso flusso del web: carico → propongo di concludere ─
	onVerbaleSelected(ev: Event) {
		const input = ev.target as HTMLInputElement;
		const file = input.files && input.files[0];
		input.value = ''; // reset per poter riselezionare lo stesso file
		if (!file) return;
		if (!this.asm?.asm_folder_id) {
			this.config.presentToastError('Cartella verbali non disponibile per questa assemblea');
			return;
		}
		const folderId = this.asm.asm_folder_id;
		this.uploadingVerbale = true;
		this.service.uploadVerbale(folderId, file).subscribe({
			next: (id) => {
				this.uploadingVerbale = false;
				if (id > 0) {
					this.config.presentToastSuccess('Verbale caricato');
					this.service.listVerbali(folderId, this.cmp_id).subscribe((v) => {
						this.verbali = v || [];
						this.proponiConcludi();
					});
				} else {
					this.config.presentToastError('Errore nel caricamento del verbale');
				}
			},
			error: () => {
				this.uploadingVerbale = false;
				this.config.presentToastError('Errore nel caricamento del verbale');
			},
		});
	}

	// dopo l'upload del verbale propone all'amministratore di concludere (mirror web onVerbaliChanged)
	private async proponiConcludi() {
		if (this.isCondomino || !this.isProgrammata) return;
		const al = await this.alertCtrl.create({
			header: 'Concludere l’assemblea?',
			message: 'Verbale caricato. Vuoi contrassegnare questa assemblea come conclusa?',
			buttons: [
				{ text: 'Non ora', role: 'cancel' },
				{
					text: 'Concludi',
					handler: () => {
						this.service.setStatus(this.asm_id, 'conclusa').subscribe({
							next: () => {
								this.config.presentToastSuccess('Assemblea conclusa');
								this.load();
							},
							error: () => this.config.presentToastError('Errore'),
						});
					},
				},
			],
		});
		await al.present();
	}
}
