// 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 { ConfigService } from '../../../providers/config.service';
import { LayoutService } from '../../../providers/layout.service';
import { AssembleeService } from '../../../providers/assemblee.service';
import { CondoUnitsService } from '../../../providers/condo-units.service';
import { Assemblea, ASSEMBLEA_TIPO_OPTIONS } from '../../../models/assemblea.model';

interface Invitato {
	cst_id: number;
	display: string;
	selected: boolean;
}

const CUSTOMER_TYPE_DITTA_INDIVIDUALE = 2;

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

	saving = false;
	// ion-datetime (keepContentsMounted) va montato solo quando la data è pronta,
	// altrimenti si inizializza su "oggi" e non si ri-sincronizza col valore caricato
	dateReady = false;
	tipoOptions = ASSEMBLEA_TIPO_OPTIONS;

	asm: Assemblea = this.empty();
	invitati: Invitato[] = [];

	constructor(
		private route: ActivatedRoute,
		private router: Router,
		private config: ConfigService,
		public layout: LayoutService,
		private service: AssembleeService,
		private condoUnits: CondoUnitsService,
	) {}

	ionViewWillEnter() {
		this.resolveIds();
		this.layout.setPageConfig({
			title: this.asm_id > 0 ? 'Modifica assemblea' : 'Nuova assemblea',
			showBack: true,
			backButtonHref: `/portale/${this.prt_id}/company/${this.cmp_id}/service/assemblee/list`,
		});
		this.loadInvitati();
	}

	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;
		}
	}

	private empty(): Assemblea {
		return {
			asm_id: 0,
			asm_cmp_id: 0,
			asm_title: '',
			asm_type: 'ordinaria',
			asm_status: 'programmata',
			asm_quorum: true,
			asm_first_call_dt: null,
			asm_second_call_dt: null,
			asm_location: '',
			asm_description: '',
			asm_odg: '',
			asm_folder_id: null,
			cst_ids: [],
		};
	}

	private loadInvitati() {
		// invitabili = condòmini (clienti Ditta Individuale) con nome
		this.condoUnits.getCustomers(this.cmp_id).subscribe({
			next: (rows) => {
				this.invitati = (rows || [])
					.filter((c: any) => Number(c.cst_type ?? c.cts_type) === CUSTOMER_TYPE_DITTA_INDIVIDUALE)
					.map((c: any) => ({
						cst_id: c.id ?? c.cst_id,
						display: ((c.name || '') + ' ' + (c.surname || '')).trim() || c.description || c.cst_display || '#' + (c.id ?? c.cst_id),
						selected: true, // di default tutti invitati
					}));
				if (this.asm_id > 0) this.loadAssemblea();
				else this.dateReady = true; // nuova: nessuna data da caricare
			},
			// clienti non caricati: il form resta comunque usabile (date incluse)
			error: () => (this.asm_id > 0 ? this.loadAssemblea() : (this.dateReady = true)),
		});
	}

	private loadAssemblea() {
		this.service.getAssemblea(this.asm_id).subscribe((a) => {
			if (!a) return;
			// non modificabile se conclusa/annullata
			if (a.asm_status !== 'programmata') {
				this.config.presentToastWarning('Assemblea conclusa o annullata: non modificabile');
				this.annulla();
				return;
			}
			// le date arrivano come "yyyy-MM-dd HH:mm:ss": ion-datetime vuole ISO con la "T"
			this.asm = { ...a, asm_first_call_dt: this.toIso(a.asm_first_call_dt), asm_second_call_dt: this.toIso(a.asm_second_call_dt) };
			this.dateReady = true; // valore pronto: ora monta ion-datetime col valore corretto
			this.service.getPartecipanti(this.asm_id).subscribe((parts) => {
				const ids = new Set((parts || []).map((p) => p.asp_cst_id));
				this.invitati.forEach((i) => (i.selected = ids.has(i.cst_id)));
			});
		});
	}

	// Il backend può restituire epoch (numero) o ISO con timezone: parso con new Date (come il web)
	// e ricostruisco un ISO LOCALE senza tz ("yyyy-MM-ddTHH:mm:ss"), che ion-datetime mostra tale e quale.
	private toIso(v: any): string | null {
		if (v === null || v === undefined || v === '') return null;
		const d = new Date(typeof v === 'string' ? v.replace(' ', 'T') : v);
		if (isNaN(d.getTime())) return null;
		const p = (n: number) => String(n).padStart(2, '0');
		return `${d.getFullYear()}-${p(d.getMonth() + 1)}-${p(d.getDate())}T${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`;
	}

	get nSelezionati(): number {
		return this.invitati.filter((i) => i.selected).length;
	}

	selezionaTutti(v: boolean) {
		this.invitati.forEach((i) => (i.selected = v));
	}

	save() {
		if (!this.asm.asm_title || !this.asm.asm_title.trim()) {
			this.config.presentToastWarning('Inserisci il titolo dell’assemblea');
			return;
		}
		if (!this.asm.asm_first_call_dt) {
			this.config.presentToastWarning('Inserisci la 1ª convocazione');
			return;
		}
		this.saving = true;
		this.asm.asm_cmp_id = this.cmp_id;
		this.asm.cst_ids = this.invitati.filter((i) => i.selected).map((i) => i.cst_id);
		const isNew = !(this.asm.asm_id > 0);
		this.service.addUpdAssemblea(this.asm).subscribe({
			next: (res) => {
				const newId = Number(res) || this.asm.asm_id;
				if (isNew && newId > 0) {
					// stesso flusso del web: cartella documentale + lettere di convocazione + notifiche (best-effort)
					this.finalizzaCreazione(newId);
				} else {
					this.concludiSalvataggio();
				}
			},
			error: () => {
				this.saving = false;
				this.config.presentToastError('Errore nel salvataggio');
			},
		});
	}

	// crea cartella verbali → genera lettere di convocazione → notifica invitati; ogni step è best-effort (non blocca)
	private finalizzaCreazione(asmId: number) {
		this.service.ensureAssembleaFolder(this.cmp_id, asmId, this.asm.asm_title || '').subscribe({
			next: () => this.generaENotifica(asmId),
			error: () => this.generaENotifica(asmId), // cartella verrà rigenerata aprendo il dettaglio
		});
	}

	private generaENotifica(asmId: number) {
		this.service.generaConvocazioni(asmId).subscribe({
			next: () => this.notificaCreazione(asmId),
			error: () => this.notificaCreazione(asmId), // template convocazione mancante: non bloccare il salvataggio
		});
	}

	private notificaCreazione(asmId: number) {
		const data = this.fmtData(this.asm.asm_first_call_dt);
		const luogo = this.asm.asm_location ? ' - ' + this.asm.asm_location : '';
		const titolo = 'Nuova assemblea: ' + (this.asm.asm_title || '');
		const msgIt = `Sei convocato all'assemblea "${this.asm.asm_title}" del ${data}${luogo}. Accedi al portale per i dettagli e per confermare la tua presenza.`;
		const msgEn = `You are invited to the assembly "${this.asm.asm_title}" on ${data}${luogo}. Log in to the portal for details and to confirm your attendance.`;
		this.service.notifyInvitati(asmId, 'assemblea_creata', titolo, msgIt, msgEn).subscribe({
			next: () => this.concludiSalvataggio(),
			error: () => this.concludiSalvataggio(),
		});
	}

	private concludiSalvataggio() {
		this.saving = false;
		this.config.presentToastSuccess('Assemblea salvata');
		this.router.navigate([`/portale/${this.prt_id}/company/${this.cmp_id}/service/assemblee/list`]);
	}

	private fmtData(v: any): string {
		if (!v) return '';
		const d = new Date(typeof v === 'string' ? v.replace(' ', 'T') : v);
		if (isNaN(d.getTime())) return '';
		const p = (n: number) => String(n).padStart(2, '0');
		return `${p(d.getDate())}/${p(d.getMonth() + 1)}/${d.getFullYear()} ${p(d.getHours())}:${p(d.getMinutes())}`;
	}

	annulla() {
		this.router.navigate([`/portale/${this.prt_id}/company/${this.cmp_id}/service/assemblee/list`]);
	}
}
