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

import { ConfigService } from './config.service';

/**
 * Descrizione della tipologia cliente usata per i clienti creati automaticamente da
 * ordini online-shop / prenotazioni: rappresenta il "privato/individuo", stessa scelta
 * del portale web (i condòmini sono "Ditta individuale"). L'id NON è cablato: viene
 * risolto a runtime leggendo cmp_company_type (companies/get_tipologia_impresa), perché
 * cts_type è un dato per-DB senza foreign key e può variare tra ambienti/tenant.
 */
const CST_TYPE_DESCRIPTION = 'Ditta individuale';
/** Fallback se la tipologia non è risolvibile (valore storico noto = Ditta individuale). */
const CST_TYPE_FALLBACK = 2;

/**
 * Registra automaticamente l'utente loggato come CLIENTE dell'azienda (+ DIPENDENTE
 * collegato) dopo un ordine online-shop o una prenotazione andati a buon fine.
 *
 * Backend: ws_spring_cmp (serviceUrl_Companies), stessi endpoint del portale web.
 * Regola di business: un solo cliente per azienda collegato allo stesso utente
 * (dedup tramite assemblee/mycustomer → cmp_get_customer_by_user, che risale dal
 * dipendente/collaboratore con userid_pt = usr_id).
 *
 * Il legame utente↔cliente è il "dipendente" (Collaborator): un utente può essere
 * dipendente di un cliente di un'azienda.
 */
@Injectable({ providedIn: 'root' })
export class CustomerRegistrationService {
	constructor(
		private http: HttpClient,
		private config: ConfigService,
	) {}

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

	/**
	 * Garantisce che l'utente loggato sia cliente dell'azienda (get-or-create idempotente).
	 * Non bloccante: qualsiasi errore viene ingoiato (l'ordine/prenotazione resta valido).
	 * Ritorna il cst_id (esistente o appena creato), 0 se non è stato possibile.
	 */
	ensureCustomerForCurrentUser(cmp_id: number): Observable<number> {
		const u = this.config.getUser();
		if (!cmp_id || !u || !(u.usr_id > 0)) return of(0);

		return this.getMyCustomer(cmp_id).pipe(
			switchMap((cstId) => {
				if (cstId > 0) return of(cstId); // già cliente di questa azienda
				return this.resolveCustomerType().pipe(
					switchMap((cstType) => this.createCustomer(cmp_id, u, cstType)),
					switchMap((newCstId) => {
						if (!(newCstId > 0)) return of(0);
						// crea il dipendente che lega l'utente al nuovo cliente
						return this.createDipendente(cmp_id, newCstId, u).pipe(map(() => newCstId));
					}),
				);
			}),
			catchError(() => of(0)),
		);
	}

	/** cst_id del cliente collegato all'utente loggato in questa azienda (0 se non collegato). */
	private 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));
	}

	/** Risolve l'id tipologia "Ditta individuale" da cmp_company_type; fallback al valore noto. */
	private resolveCustomerType(): Observable<number> {
		return this.http.get<any[]>(`${this.base}companies/get_tipologia_impresa`, { observe: 'response' }).pipe(
			map((r) => {
				const list = r.body || [];
				const match = list.find((t) => (t?.cmptp_description || '').trim().toLowerCase() === CST_TYPE_DESCRIPTION.toLowerCase());
				return Number(match?.cmptp_id) || CST_TYPE_FALLBACK;
			}),
			catchError(() => of(CST_TYPE_FALLBACK)),
		);
	}

	/** Crea il cliente (customers/add) con i dati dell'utente. Ritorna il nuovo cst_id. */
	private createCustomer(cmp_id: number, u: any, cst_type: number): Observable<number> {
		const cst = {
			cmp_id,
			name: u.usr_firstname || u.usr_displayname || '',
			surname: u.usr_lastname || '',
			description: (u.usr_displayname || `${u.usr_firstname || ''} ${u.usr_lastname || ''}`).trim(),
			email: u.usr_mail || '',
			phonenr: u.usr_phone || '',
			tax_code: u.usr_codicefiscale || '',
			cst_type,
		};
		return this.http
			.post<number>(`${this.base}customers/add`, cst, { observe: 'response' })
			.pipe(map((r) => Number(r.body) || 0));
	}

	/** Crea il dipendente (collaborators/add) che lega l'utente (userid_pt) al cliente (cst_id). */
	private createDipendente(cmp_id: number, cst_id: number, u: any): Observable<number> {
		const col = {
			cmp_id,
			cst_id,
			sup_id: 0,
			userid_pt: u.usr_id,
			name: u.usr_firstname || u.usr_displayname || '',
			surname: u.usr_lastname || '',
			email: u.usr_mail || '',
			phonenr: u.usr_phone || '',
			col_cf: u.usr_codicefiscale || '',
		};
		return this.http
			.post<number>(`${this.base}collaborators/add`, col, { observe: 'response' })
			.pipe(map((r) => Number(r.body) || 0));
	}
}
