// 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 { FileTransfer } from '@capacitor/file-transfer';
import { Filesystem, Directory } from '@capacitor/filesystem';
import { FileOpener } from '@capawesome-team/capacitor-file-opener';
import { Platform } from '@ionic/angular';
import { LoadingController, ToastController, AlertController } from '@ionic/angular';
import { Capacitor } from '@capacitor/core';
import { HttpClient } from '@angular/common/http';

@Injectable({
	providedIn: 'root',
})
export class FileDownloadService {
	constructor(private platform: Platform, private loadingCtrl: LoadingController, private toastCtrl: ToastController, private alertCtrl: AlertController, private http: HttpClient) {}

	async downloadAndOpenFile(fileUrl: string, fileName: string, mimeType?: string): Promise<void> {
		const loading = await this.loadingCtrl.create({
			message: 'Attesa apertura file...',
			spinner: 'circular',
		});

		try {
			await loading.present();

			if (Capacitor.isNativePlatform()) {
				try {
					await Filesystem.rmdir({ path: 'file-transfer', directory: Directory.Documents, recursive: true });
				} catch (e) {
					// la cartella può non esistere al primo download: ignoro
				}
				await Filesystem.mkdir({
					path: 'file-transfer',
					directory: Directory.Documents,
					recursive: true,
				});

				await this.downloadWithFileTransfer(fileUrl, fileName, mimeType, loading);
			} else {
				// Web platform
				await this.downloadForWeb(fileUrl, fileName);
				await loading.dismiss();
			}
		} catch (error: any) {
			await loading.dismiss();
			await this.showError('Failed to download or open file: ' + error.message);
			throw error;
		}
	}

	private async downloadWithFileTransfer(fileUrl: string, fileName: string, mimeType?: string, loading?: HTMLIonLoadingElement): Promise<void> {
		try {
			const url = fileUrl;
			let filePath = '';

			const pathResult = await Filesystem.getUri({
				path: 'file-transfer-test/' + fileName,
				directory: Directory.Documents,
			});
			filePath = pathResult.uri;

			// Download file
			const result = await FileTransfer.downloadFile({
				url,
				path: filePath,
				progress: false,
			});

			if (loading) {
				await loading.dismiss();
			}

			if (result && result.path) {
				await this.openFile(result.path, mimeType || this.getMimeType(fileName));
			} else {
				const directory = this.platform.is('ios') ? Directory.Documents : Directory.Data;
				const fileUri = await this.getFileUri(fileName, directory);
				if (fileUri) {
					await this.openFile(fileUri, mimeType || this.getMimeType(fileName));
				}
			}
		} catch (error) {
			console.error('FileTransfer download error:', error);
			if (loading) {
				await loading.dismiss();
			}
			throw error;
		}
	}

	private async getFileUri(fileName: string, directory: Directory): Promise<string | null> {
		try {
			const result = await Filesystem.stat({
				path: fileName,
				directory: directory,
			});
			return result.uri;
		} catch (error) {
			console.error('Could not get file URI:', error);
			return null;
		}
	}

	private async openFile(filePath: string, mimeType: string): Promise<void> {
		try {
			// Use the correct method name: open() instead of openFile()
			await FileOpener.openFile({
				path: filePath,
				mimeType: mimeType,
			});
		} catch (error: any) {
			// Fallback: Show options to user
			await this.showOpenFileError(filePath);
			throw new Error('Could not open file: ' + error.message);
		}
	}

	/**
	 * Fallback for web platform
	 */
	private async downloadForWeb(fileUrl: string, fileName: string): Promise<void> {
		// For web, we'll try a different approach
		try {
			// Try to fetch the file
			const response = await fetch(fileUrl);
			const blob = await response.blob();

			// Create object URL
			const url = window.URL.createObjectURL(blob);

			// Create download link
			const link = document.createElement('a');
			link.href = url;
			link.download = fileName;
			link.style.display = 'none';
			document.body.appendChild(link);
			link.click();

			// Cleanup
			document.body.removeChild(link);
			window.URL.revokeObjectURL(url);
		} catch (error) {
			// If CORS blocks fetch, fall back to direct link
			const link = document.createElement('a');
			link.href = fileUrl;
			link.download = fileName;
			link.target = '_blank';
			document.body.appendChild(link);
			link.click();
			document.body.removeChild(link);
		}
	}

	private async showOpenFileError(filePath: string): Promise<void> {
		const alert = await this.alertCtrl.create({
			header: 'Cannot Open File',
			message: 'The file was downloaded successfully but cannot be opened. Would you like to try a different app?',
			buttons: [
				{
					text: 'Cancel',
					role: 'cancel',
				},
				{
					text: 'Share File',
					handler: async () => {
						// Use Capacitor Share API as fallback
						if (Capacitor.isPluginAvailable('Share')) {
							const { Share } = await import('@capacitor/share');
							await Share.share({
								title: 'Downloaded File',
								url: filePath,
							});
						}
					},
				},
			],
		});
		await alert.present();
	}

	getMimeType(fileName: string): string {
		const extension = fileName.split('.').pop()?.toLowerCase();

		const mimeTypes: { [key: string]: string } = {
			// Images
			jpg: 'image/jpeg',
			jpeg: 'image/jpeg',
			png: 'image/png',
			gif: 'image/gif',
			bmp: 'image/bmp',
			webp: 'image/webp',
			svg: 'image/svg+xml',

			// Documents
			pdf: 'application/pdf',
			doc: 'application/msword',
			docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
			xls: 'application/vnd.ms-excel',
			xlsx: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
			ppt: 'application/vnd.ms-powerpoint',
			pptx: 'application/vnd.openxmlformats-officedocument.presentationml.presentation',

			// Text
			txt: 'text/plain',
			csv: 'text/csv',
			json: 'application/json',
			xml: 'text/xml',

			// Video
			mp4: 'video/mp4',
			avi: 'video/x-msvideo',
			mov: 'video/quicktime',
			wmv: 'video/x-ms-wmv',

			// Audio
			mp3: 'audio/mpeg',
			wav: 'audio/wav',
			ogg: 'audio/ogg',
			m4a: 'audio/mp4',
		};

		return extension ? mimeTypes[extension] || 'application/octet-stream' : 'application/octet-stream';
	}

	/**
	 * Show error toast
	 */
	private async showError(message: string): Promise<void> {
		const toast = await this.toastCtrl.create({
			message: message,
			duration: 3000,
			position: 'bottom',
			color: 'danger',
			buttons: [
				{
					text: 'Dismiss',
					role: 'cancel',
				},
			],
		});
		await toast.present();
	}

	/**
	 * Check if file exists locally
	 */
	async fileExists(fileName: string): Promise<boolean> {
		try {
			const directory = this.platform.is('ios') ? Directory.Documents : Directory.Data;

			await Filesystem.stat({
				path: fileName,
				directory: directory,
			});
			return true;
		} catch {
			return false;
		}
	}

	/**
	 * Delete a file from local storage
	 */
	async deleteFile(fileName: string): Promise<void> {
		try {
			const directory = this.platform.is('ios') ? Directory.Documents : Directory.Data;

			await Filesystem.deleteFile({
				path: fileName,
				directory: directory,
			});
		} catch (error) {
			console.error('Error deleting file:', error);
		}
	}

	/**
	 * Get list of downloaded files
	 */
	async getDownloadedFiles(): Promise<any[]> {
		try {
			const directory = this.platform.is('ios') ? Directory.Documents : Directory.Data;

			const result = await Filesystem.readdir({
				path: '',
				directory: directory,
			});

			return result.files || [];
		} catch (error) {
			console.error('Error reading directory:', error);
			return [];
		}
	}
}
