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

import { ConfigService } from './config.service';
import { CmpConversation, CmpMessage, UserSearchResult, CmpConversationMember } from 'src/models/messaging/conversation.model';

@Injectable({
	providedIn: 'root',
})
export class MessagingService {
	constructor(private http: HttpClient, private configService: ConfigService) {}

	private get baseUrl(): string {
		return this.configService.serviceUrl_Companies;
	}

	getConversations(): Observable<CmpConversation[]> {
		return this.http.get(`${this.baseUrl}messaging/conversations`, { observe: 'response' }).pipe(map((r: any) => r.body || []));
	}

	findOrCreateConversation(otherUsrId: number): Observable<CmpConversation> {
		return this.http.post(`${this.baseUrl}messaging/conversations/find-or-create`, { other_usr_id: otherUsrId }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	findOrCreateConversationByCompany(cmpId: number): Observable<CmpConversation> {
		return this.http.post(`${this.baseUrl}messaging/conversations/find-or-create-by-company`, { cmp_id: cmpId }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	findOrCreateCompanyConversationForClient(cmpId: number, clientUsrId: number): Observable<CmpConversation> {
		return this.http.post(`${this.baseUrl}messaging/conversations/find-or-create-company-client`, { cmp_id: cmpId, client_usr_id: clientUsrId }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	getMessages(convId: number): Observable<CmpMessage[]> {
		return this.http.get(`${this.baseUrl}messaging/messages/${convId}`, { observe: 'response' }).pipe(map((r: any) => r.body || []));
	}

	sendMessage(convId: number, text: string): Observable<CmpMessage> {
		const formData = new FormData();
		formData.append('text', text);
		return this.http.post(`${this.baseUrl}messaging/messages/send/${convId}`, formData, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	sendMedia(convId: number, text: string, files: File[]): Observable<CmpMessage> {
		const formData = new FormData();
		formData.append('text', text || '');
		(files || []).forEach((f) => formData.append('files', f));
		return this.http.post(`${this.baseUrl}messaging/messages/send-media/${convId}`, formData, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	editMessage(msgId: number, text: string): Observable<number> {
		return this.http.put(`${this.baseUrl}messaging/messages/edit/${msgId}`, { text }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	getAttachmentBlob(attId: number): Observable<Blob> {
		return this.http.get(`${this.baseUrl}messaging/attachments/${attId}`, { responseType: 'blob' });
	}

	markAsRead(convId: number): Observable<number> {
		return this.http.put(`${this.baseUrl}messaging/messages/read/${convId}`, {}, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	getUnreadCount(): Observable<number> {
		return this.http.get(`${this.baseUrl}messaging/unread-count`, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	deleteMessage(msgId: number): Observable<any> {
		return this.http.delete(`${this.baseUrl}messaging/messages/${msgId}`, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	deleteConversation(convId: number): Observable<any> {
		return this.http.delete(`${this.baseUrl}messaging/conversations/${convId}`, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	searchUsers(txtsearch: string): Observable<UserSearchResult[]> {
		return this.http.get(`${this.baseUrl}messaging/users?txtsearch=${encodeURIComponent(txtsearch)}`, { observe: 'response' }).pipe(map((r: any) => r.body || []));
	}

	/** Ricerca full-text nei contenuti dei messaggi: ritorna conv_id + snippet del match. */
	searchMessages(txtsearch: string): Observable<{ conv_id: number; snippet: string }[]> {
		return this.http.get(`${this.baseUrl}messaging/messages/search?txtsearch=${encodeURIComponent(txtsearch)}`, { observe: 'response' }).pipe(map((r: any) => r.body || []));
	}

	/** Ricerca peer per i gruppi: tutte le aziende dell'utente, indipendente da cmp_chat_mode. */
	searchGroupUsers(txtsearch: string): Observable<UserSearchResult[]> {
		return this.http.get(`${this.baseUrl}messaging/group-users?txtsearch=${encodeURIComponent(txtsearch)}`, { observe: 'response' }).pipe(map((r: any) => r.body || []));
	}

	// --- Gruppi ---

	createGroup(title: string, memberIds: number[]): Observable<CmpConversation> {
		return this.http.post(`${this.baseUrl}messaging/groups`, { title, member_ids: memberIds }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	getGroupMembers(convId: number): Observable<CmpConversationMember[]> {
		return this.http.get(`${this.baseUrl}messaging/groups/${convId}/members`, { observe: 'response' }).pipe(map((r: any) => r.body || []));
	}

	addGroupMember(convId: number, usrId: number): Observable<any> {
		return this.http.post(`${this.baseUrl}messaging/groups/${convId}/members`, { usr_id: usrId }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	removeGroupMember(convId: number, usrId: number): Observable<any> {
		return this.http.delete(`${this.baseUrl}messaging/groups/${convId}/members/${usrId}`, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	leaveGroup(convId: number): Observable<any> {
		return this.http.post(`${this.baseUrl}messaging/groups/${convId}/leave`, {}, { observe: 'response' }).pipe(map((r: any) => r.body));
	}

	renameGroup(convId: number, title: string): Observable<any> {
		return this.http.put(`${this.baseUrl}messaging/groups/${convId}`, { title }, { observe: 'response' }).pipe(map((r: any) => r.body));
	}
}
