// 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, OnInit, ViewChild } from '@angular/core';
import { Router } from '@angular/router';
import { ActionSheetController, IonModal } from '@ionic/angular';

import { MessagingService } from 'src/app/providers/messaging.service';
import { LayoutService } from 'src/app/providers/layout.service';
import { ContactsService } from 'src/app/providers/contacts.service';
import { ConfigService } from 'src/app/providers/config.service';
import { CmpConversation, UserSearchResult } from 'src/models/messaging/conversation.model';

@Component({
	standalone: false,
	selector: 'app-messaging',
	templateUrl: './messaging.page.html',
	styleUrls: ['./messaging.page.scss'],
})
export class MessagingPage implements OnInit {
	conversations: CmpConversation[] = [];
	filteredConversations: CmpConversation[] = [];
	searchText = '';
	// conv_id -> snippet del messaggio che combacia (ricerca nei contenuti, lato server)
	messageMatches = new Map<number, string>();
	private convSearchTimer: any;
	loading: boolean = false;
	showContactsModal = false;
	contactsLoading = false;

	// Nuova conversazione DIRECT (ricerca membri della propria azienda)
	@ViewChild('newChatModal') newChatModal?: IonModal;
	showNewChatModal = false;
	userSearchText = '';
	userResults: UserSearchResult[] = [];
	searchingUsers = false;

	// Modalità creazione gruppo
	groupMode = false;
	groupName = '';
	selectedMembers: UserSearchResult[] = [];

	private longPressTimer: any;
	private longPressFired = false;
	private userSearchTimer: any;

	constructor(private router: Router, private messagingService: MessagingService, private layoutService: LayoutService, private actionSheetCtrl: ActionSheetController, public contactsService: ContactsService, private configService: ConfigService) {}

	ngOnInit(): void {
		this.loadConversations();
	}

	ionViewWillEnter(): void {
		this.layoutService.setPageConfig({ showBack: false, title: 'Messaggi', rightButton: null });
		this.initContacts();
	}

	private initContacts(): void {
		if (this.contactsService.isLoaded()) return;

		if (!this.contactsService.hasBeenAsked()) {
			// Mostra modal stile location dopo un breve delay
			setTimeout(() => {
				this.showContactsModal = true;
			}, 700);
		} else {
			// Permesso già gestito: carica silenziosamente se concesso
			this.contactsService.loadIfPermitted();
		}
	}

	async acceptContacts(): Promise<void> {
		this.showContactsModal = false;
		this.contactsLoading = true;
		await this.contactsService.requestAndLoad();
		this.contactsLoading = false;
	}

	declineContacts(): void {
		this.showContactsModal = false;
		this.contactsService.markAsAsked();
	}

	loadConversations(): void {
		this.loading = true;
		this.messagingService.getConversations().subscribe({
			next: (data: CmpConversation[]) => {
				this.conversations = data || [];
				this.applyConvFilter();
			},
			error: () => {
				this.loading = false;
				this.conversations = [];
				this.applyConvFilter();
			},
			complete: () => {
				this.loading = false;
			},
		});
	}

	// --- Ricerca chat (stile WhatsApp: per nome o testo messaggio) ---

	onConvSearchInput(): void {
		// Filtro locale immediato (nome/username/ultimo messaggio)
		this.applyConvFilter();

		// Ricerca nei contenuti dei messaggi lato server (debounce)
		if (this.convSearchTimer) clearTimeout(this.convSearchTimer);
		const term = (this.searchText || '').trim();
		if (!term) {
			this.messageMatches.clear();
			return;
		}
		this.convSearchTimer = setTimeout(() => {
			this.messagingService.searchMessages(term).subscribe({
				next: (matches) => {
					// Ignora risposte stale se nel frattempo il termine è cambiato
					if ((this.searchText || '').trim() !== term) return;
					this.messageMatches = new Map((matches || []).map((m) => [m.conv_id, m.snippet]));
					this.applyConvFilter();
				},
			});
		}, 300);
	}

	onConvSearchClear(): void {
		this.searchText = '';
		this.messageMatches.clear();
		if (this.convSearchTimer) clearTimeout(this.convSearchTimer);
		this.applyConvFilter();
	}

	private applyConvFilter(): void {
		const term = (this.searchText || '').toLowerCase().trim();
		if (!term) {
			this.filteredConversations = [...this.conversations];
			return;
		}
		this.filteredConversations = this.conversations.filter((conv) => {
			const name = this.getOtherName(conv).toLowerCase();
			const last = (conv.last_message_text || '').toLowerCase();
			const username = (conv.other_username || '').toLowerCase();
			return name.includes(term) || last.includes(term) || username.includes(term) || this.messageMatches.has(conv.conv_id);
		});
	}

	/** Anteprima da mostrare in lista: durante una ricerca, se il match è nel contenuto
	 *  di un messaggio (non nell'ultimo), mostra lo snippet del messaggio trovato. */
	getConvPreview(conv: CmpConversation): string {
		const term = (this.searchText || '').toLowerCase().trim();
		if (term) {
			const last = (conv.last_message_text || '').toLowerCase();
			// Se l'ultimo messaggio non combacia ma esiste un match nel contenuto, mostra lo snippet
			if (!last.includes(term) && this.messageMatches.has(conv.conv_id)) {
				const snippet = this.messageMatches.get(conv.conv_id) || '';
				const t = snippet.trim();
				return t.length > 55 ? t.substring(0, 55) + '...' : t;
			}
		}
		return this.getPreview(conv);
	}

	doRefresh(event: any): void {
		this.messagingService.getConversations().subscribe({
			next: (data: CmpConversation[]) => {
				this.conversations = data || [];
				this.applyConvFilter();
			},
			complete: () => event.target.complete(),
			error: () => event.target.complete(),
		});
	}

	openChat(conv: CmpConversation): void {
		// Il click sintetico dopo un long-press non deve aprire la chat
		// mentre e' visibile l'action sheet di eliminazione.
		if (this.longPressFired) {
			this.longPressFired = false;
			return;
		}
		this.router.navigate(['/messaging/chat', conv.conv_id], {
			state: {
				chatWith: conv.other_company_name || this.getOtherName(conv),
				isCompany: !!conv.other_company_name,
				isGroup: conv.conv_type === 'GROUP',
				cmpId: conv.other_cmp_id || null,
				prtId: conv.other_prt_id || null,
				otherUsername: conv.other_username || null,
			},
		});
	}

	getOtherName(conv: CmpConversation): string {
		if (conv.other_company_name) return conv.other_company_name;
		// Se lo username (numero di telefono) è in rubrica, usa il nome della rubrica
		const contactName = this.contactsService.getNameByPhone(conv.other_username);
		if (contactName) return contactName;
		return [conv.other_lastname, conv.other_firstname].filter(Boolean).join(' ') || 'Utente';
	}

	getInitials(conv: CmpConversation): string {
		if (conv.other_company_name) {
			return conv.other_company_name.substring(0, 2).toUpperCase();
		}
		const name = this.getOtherName(conv);
		const words = name.trim().split(/\s+/);
		if (words.length >= 2) return (words[0][0] + words[1][0]).toUpperCase();
		return name.substring(0, 2).toUpperCase();
	}

	getPreview(conv: CmpConversation): string {
		// null/undefined = nessun messaggio; stringa vuota = messaggio di solo allegato
		if (conv.last_message_text == null) return 'Nessun messaggio';
		const t = conv.last_message_text.trim();
		if (!t) return '📎 Allegato';
		return t.length > 55 ? t.substring(0, 55) + '...' : t;
	}

	onConvTouchStart(conv: CmpConversation, event: TouchEvent): void {
		this.longPressFired = false;
		this.longPressTimer = setTimeout(async () => {
			this.longPressFired = true;
			const sheet = await this.actionSheetCtrl.create({
				buttons: [
					{
						text: 'Elimina conversazione',
						role: 'destructive',
						icon: 'trash-outline',
						handler: () => this.confirmDeleteConversation(conv),
					},
					{
						text: 'Annulla',
						role: 'cancel',
					},
				],
			});
			await sheet.present();
		}, 600);
	}

	onConvTouchEnd(): void {
		if (this.longPressTimer) clearTimeout(this.longPressTimer);
	}

	private confirmDeleteConversation(conv: CmpConversation): void {
		this.messagingService.deleteConversation(conv.conv_id).subscribe({
			next: () => {
				this.conversations = this.conversations.filter((c) => c.conv_id !== conv.conv_id);
				this.applyConvFilter();
			},
		});
	}

	// --- Nuova conversazione DIRECT ---

	openNewChat(): void {
		this.userSearchText = '';
		this.userResults = [];
		this.groupMode = false;
		this.groupName = '';
		this.selectedMembers = [];
		this.showNewChatModal = true;
	}

	closeNewChat(): void {
		this.showNewChatModal = false;
		this.userResults = [];
		this.userSearchText = '';
		this.groupMode = false;
		this.groupName = '';
		this.selectedMembers = [];
	}

	// Attende la chiusura effettiva dello sheet prima di navigare: navigare
	// durante l'animazione di dismiss lascia il modal bloccato sopra la chat
	private async dismissNewChatAndNavigate(convId: number, state: any): Promise<void> {
		try {
			await this.newChatModal?.dismiss();
		} catch {}
		this.closeNewChat();
		this.router.navigate(['/messaging/chat', convId], { state });
	}

	toggleGroupMode(): void {
		this.groupMode = !this.groupMode;
		this.selectedMembers = [];
	}

	isMemberSelected(user: UserSearchResult): boolean {
		return this.selectedMembers.some((m) => m.usr_id === user.usr_id);
	}

	toggleMemberSelection(user: UserSearchResult): void {
		if (this.isMemberSelected(user)) {
			this.selectedMembers = this.selectedMembers.filter((m) => m.usr_id !== user.usr_id);
		} else {
			this.selectedMembers = [...this.selectedMembers, user];
		}
	}

	createGroup(): void {
		const title = (this.groupName || '').trim();
		if (!title || this.selectedMembers.length === 0) return;
		const ids = this.selectedMembers.map((m) => m.usr_id);
		this.messagingService.createGroup(title, ids).subscribe({
			next: (conv: CmpConversation) => {
				this.dismissNewChatAndNavigate(conv.conv_id, { chatWith: title, isCompany: true, isGroup: true });
			},
			error: () => this.configService.presentToastError('Errore creazione gruppo'),
		});
	}

	onUserSearchInput(): void {
		if (this.userSearchTimer) clearTimeout(this.userSearchTimer);
		const txt = (this.userSearchText || '').trim();
		this.userSearchTimer = setTimeout(() => {
			this.searchingUsers = true;
			// In modalità gruppo cerca tra TUTTI i peer (qualsiasi modalità); per il 1:1 solo aziende DIRECT
			const search$ = this.groupMode ? this.messagingService.searchGroupUsers(txt) : this.messagingService.searchUsers(txt);
			search$.subscribe({
				next: (res: UserSearchResult[]) => {
					this.userResults = res || [];
				},
				complete: () => {
					this.searchingUsers = false;
				},
				error: () => {
					this.searchingUsers = false;
					this.userResults = [];
				},
			});
		}, 300);
	}

	startChatWith(user: UserSearchResult): void {
		this.messagingService.findOrCreateConversation(user.usr_id).subscribe({
			next: (conv: CmpConversation) => {
				this.dismissNewChatAndNavigate(conv.conv_id, {
					chatWith: [user.usr_firstname, user.usr_lastname].filter(Boolean).join(' '),
					isCompany: false,
					otherUsername: user.usr_username || null,
				});
			},
		});
	}

	getUserInitials(user: UserSearchResult): string {
		const a = (user.usr_firstname || '').charAt(0);
		const b = (user.usr_lastname || '').charAt(0);
		return (a + b).toUpperCase() || (user.usr_username || '?').substring(0, 2).toUpperCase();
	}

	getTimeAgo(dateStr: string): string {
		if (!dateStr) return '';
		const date = new Date(dateStr);
		const now = new Date();
		const diff = now.getTime() - date.getTime();
		const minutes = Math.floor(diff / 60000);
		if (minutes < 1) return 'ora';
		if (minutes < 60) return `${minutes}m`;
		const hours = Math.floor(minutes / 60);
		if (hours < 24) return `${hours}h`;
		const days = Math.floor(hours / 24);
		if (days < 7) return `${days}g`;
		return date.toLocaleDateString('it-IT', { day: '2-digit', month: '2-digit' });
	}
}
