// 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 { Observable, of, forkJoin } from 'rxjs';
import { map, switchMap } from 'rxjs/operators';

import { ConfigService } from './config.service';
import { Assemblea, AssembleaPartecipante, ConvocazioneLettera } from '../models/assemblea.model';

// Radice della documentale ("Document Management"): sotto vive la cartella di ogni condominio (come il web)
const ROOT_DOCUMENT_MANAGEMENT = 2;

/**
 * Assemblee condominiali — stesso backend del portale web (ws_spring_cmp, serviceUrl_Companies).
 * Endpoint /assemblee/* e /documenti/convocazioni/*.
 */
@Injectable({ providedIn: 'root' })
export class AssembleeService {
	constructor(
		private http: HttpClient,
		private config: ConfigService,
	) {}

	private get base(): string {
		return this.config.serviceUrl_Companies;
	}

	getAssemblee(cmp_id: number, txtsearch = '', order_by = 'asm_first_call_dt DESC', limit = 100, offset = 1, status = ''): Observable<Assemblea[]> {
		const url = `${this.base}assemblee/list?cmp_id=${cmp_id}&txtsearch=${encodeURIComponent(txtsearch)}&order_by=${encodeURIComponent(order_by)}&limit=${limit}&offset=${offset}&stato=${encodeURIComponent(status)}`;
		return this.http.get<Assemblea[]>(url, { observe: 'response' }).pipe(map((r) => r.body || []));
	}

	getAssemblea(asm_id: number): Observable<Assemblea> {
		return this.http.get<Assemblea>(`${this.base}assemblee/get?asm_id=${asm_id}`, { observe: 'response' }).pipe(map((r) => r.body as Assemblea));
	}

	addUpdAssemblea(asm: Assemblea): Observable<number> {
		const url = asm.asm_id > 0 ? `${this.base}assemblee/upd` : `${this.base}assemblee/add`;
		return this.http.post<number>(url, asm, { observe: 'response' }).pipe(map((r) => r.body as number));
	}

	delAssemblea(asm_id: number): Observable<any> {
		return this.http.delete(`${this.base}assemblee/del/${asm_id}`, { observe: 'response' }).pipe(map((r) => r.body));
	}

	getPartecipanti(asm_id: number): Observable<AssembleaPartecipante[]> {
		return this.http.get<AssembleaPartecipante[]>(`${this.base}assemblee/partecipanti?asm_id=${asm_id}`, { observe: 'response' }).pipe(map((r) => r.body || []));
	}

	updateRsvp(p: AssembleaPartecipante): Observable<any> {
		return this.http.post(`${this.base}assemblee/rsvp`, p, { observe: 'response' }).pipe(map((r) => r.body));
	}

	/** cst_id del condomino associato all'utente loggato (0 se non è un condomino → è un gestore). */
	getMyCustomer(cmp_id: number): Observable<number> {
		return this.http.get<number>(`${this.base}assemblee/mycustomer?cmp_id=${cmp_id}`, { observe: 'response' }).pipe(map((r) => Number(r.body) || 0));
	}

	/** stato: programmata | conclusa | annullata */
	setStatus(asm_id: number, status: string): Observable<any> {
		return this.http.post(`${this.base}assemblee/setstatus?asm_id=${asm_id}&status=${status}`, null, { observe: 'response' }).pipe(map((r) => r.body));
	}

	// --- Lettere di convocazione (generate da template, una per referente) ---

	generaConvocazioni(asm_id: number): Observable<number> {
		return this.http.post<number>(`${this.base}documenti/convocazioni/genera?asm_id=${asm_id}`, null, { observe: 'response' }).pipe(map((r) => r.body as number));
	}

	listConvocazioni(asm_id: number): Observable<ConvocazioneLettera[]> {
		return this.http.get<ConvocazioneLettera[]>(`${this.base}documenti/convocazioni?asm_id=${asm_id}`, { observe: 'response' }).pipe(map((r) => r.body || []));
	}

	/** Verbali: file caricati nella cartella documentale dell'assemblea (asm_folder_id). */
	listVerbali(folderId: number, cmp_id: number): Observable<any[]> {
		const filter = { id_folder: folderId, cmp_id: cmp_id, pagina: 1, righePagina: 1000, orderBy: 'drfl_id desc', stato: '-1', search_sottocartelle: false, campi_form: '' };
		return this.http.post<any>(`${this.config.serviceUrl_Documentary}file/get_lista_file`, filter, { observe: 'response' }).pipe(map((r) => (Array.isArray(r.body) ? r.body : r.body?.files || [])));
	}

	/**
	 * Carica un verbale (PDF) nella cartella documentale dell'assemblea — stesso flusso a 2 step del web:
	 * 1) upload in temp (insert_pdf_file_in_folder_temp) → path; 2) registrazione (insert_new_file). Ritorna il drfl_id (>0 = ok).
	 */
	uploadVerbale(folderId: number, file: File): Observable<number> {
		const fd1 = new FormData();
		fd1.append('fileUpload[]', file);
		return this.http.post<{ res: string }>(`${this.config.serviceUrl_Documentary}file/insert_pdf_file_in_folder_temp`, fd1, { observe: 'response' }).pipe(
			map((r) => r.body?.res || ''),
			switchMap((tempPath) => {
				if (!tempPath) return of(0);
				const fd2 = new FormData();
				fd2.append('metadata_file', '{}');
				fd2.append('file_path', tempPath);
				fd2.append('original_file_name', file.name);
				fd2.append('drfl_description', '');
				return this.http.post<number>(`${this.config.serviceUrl_Documentary}file/insert_new_file/${folderId}`, fd2, { observe: 'response' }).pipe(map((r) => Number(r.body) || 0));
			}),
		);
	}

	// ─── Creazione "completa" come il web: cartella documentale + notifiche ───────────────

	/** Collega una cartella documentale all'assemblea. */
	setFolder(asm_id: number, folder_id: number): Observable<any> {
		return this.http.post(`${this.base}assemblee/setfolder?asm_id=${asm_id}&folder_id=${folder_id}`, null, { observe: 'response' }).pipe(map((r) => r.body));
	}

	/**
	 * Garantisce la cartella verbali dell'assemblea e la collega (get-or-create idempotente, come EnsureAssembleaFolder del web):
	 * ROOT / <Condominio> / Assemblee / <id - titolo>. Recupera da sola il nome del condominio. Ritorna il folder_id foglia.
	 */
	ensureAssembleaFolder(cmp_id: number, asm_id: number, title: string): Observable<number> {
		return this.http.get<any>(`${this.base}companies/get?cmp_id=${cmp_id}`, { observe: 'response' }).pipe(
			map((r) => (r.body?.name as string) || ''),
			switchMap((companyName: string) => {
				const names = [companyName, 'Assemblee', asm_id + ' - ' + title];
				const leaf$ = names.reduce(
					(acc$: Observable<number>, name: string) => acc$.pipe(switchMap((parentId: number) => this.getOrCreateFolder(name, parentId, cmp_id))),
					of(ROOT_DOCUMENT_MANAGEMENT) as Observable<number>,
				);
				return leaf$.pipe(switchMap((leafId: number) => this.setFolder(asm_id, leafId).pipe(map(() => leafId))));
			}),
		);
	}

	private getOrCreateFolder(name: string, idParent: number, cmp_id: number): Observable<number> {
		const folder = { view_name: name, id_parent: idParent, drfrm_id: 0 };
		return this.http
			.post<any>(`${this.config.serviceUrl_Documentary}folder/verifyFolderExists/${cmp_id}`, folder, { observe: 'response' })
			.pipe(map((r) => (typeof r.body === 'number' ? r.body : r.body?.id || 0)));
	}

	/** Notifica push (in-app) + email agli invitati con utenza portale. Ritorna il numero di destinatari. */
	notifyInvitati(asm_id: number, tipo: string, titolo: string, msgIt: string, msgEn: string): Observable<number> {
		return this.getPartecipanti(asm_id).pipe(
			switchMap((parts) => {
				const recipients = (parts || []).filter((p) => p.cst_userid_pt && p.cst_userid_pt > 0).map((p) => ({ usrnot_usr_id: p.cst_userid_pt as number }));
				if (recipients.length === 0) return of(0);
				const req: any = {
					recipients,
					usrnot_type: tipo,
					usrnot_title: titolo,
					usrnot_message_it: msgIt,
					usrnot_message_en: msgEn,
					usrnot_message_html_it: '<p>' + msgIt + '</p>',
					usrnot_message_html_en: '<p>' + msgEn + '</p>',
					usrnot_image: null,
				};
				const url = `${this.config.serviceUrl_PortalManager}notify/add-batch`;
				// canale Push (in-app, typesent '') + canale email (typesent 'M')
				return forkJoin([
					this.http.post(url, { ...req, usrnot_typesent: '' }, { observe: 'response' }),
					this.http.post(url, { ...req, usrnot_typesent: 'M' }, { observe: 'response' }),
				]).pipe(map(() => recipients.length));
			}),
		);
	}
}
