// 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

using System;
using System.IO;
using System.Net;

namespace KondorCS.ScheduleLibrary.AIFileProcessor
{
    /// <summary>
    /// Servizio per gestire il download di file tramite FTP da una macchina remota
    /// </summary>
    public class MediaDownloadService
    {
        private string mFtpHost;
        private string mFtpUsername;
        private string mFtpPassword;
        private string mTempFolder;
        private string mFtpBasePath;
        private bool mDebug;

        public MediaDownloadService(bool debug = false)
        {
            mDebug = debug;
        }

        /// <summary>
        /// Inizializza la configurazione del servizio FTP
        /// </summary>
        /// <param name="ftpHost">Host FTP (es: ftp://192.168.1.100 o ftp://server.com)</param>
        /// <param name="ftpUsername">Username FTP</param>
        /// <param name="ftpPassword">Password FTP</param>
        /// <param name="tempFolder">Cartella locale per i file temporanei</param>
        /// <param name="ftpBasePath">Path base da rimuovere (opzionale, es: /var/www/html/assets)</param>
        public void Initialize(string ftpHost, string ftpUsername, string ftpPassword, string tempFolder, string ftpBasePath = null)
        {
            mFtpHost = ftpHost;
            mFtpUsername = ftpUsername;
            mFtpPassword = ftpPassword;
            mTempFolder = tempFolder;
            mFtpBasePath = ftpBasePath;

            // Assicura che l'host FTP inizi con ftp://
            if (!string.IsNullOrEmpty(mFtpHost) && !mFtpHost.StartsWith("ftp://", StringComparison.OrdinalIgnoreCase))
            {
                mFtpHost = "ftp://" + mFtpHost;
            }

            // Rimuovi lo slash finale se presente
            if (!string.IsNullOrEmpty(mFtpHost) && mFtpHost.EndsWith("/"))
            {
                mFtpHost = mFtpHost.TrimEnd('/');
            }

            // Normalizza il base path se presente
            if (!string.IsNullOrEmpty(mFtpBasePath))
            {
                // Converti backslash in forward slash
                mFtpBasePath = mFtpBasePath.Replace('\\', '/');
                // Rimuovi slash finale se presente
                mFtpBasePath = mFtpBasePath.TrimEnd('/');
            }

            // Crea la cartella temporanea se non esiste
            if (!Directory.Exists(mTempFolder))
            {
                Directory.CreateDirectory(mTempFolder);
                if (mDebug)
                    Console.WriteLine($"[FTP] Cartella temporanea creata: {mTempFolder}");
            }

            if (mDebug)
            {
                Console.WriteLine($"[FTP] Configurazione FTP: Host={mFtpHost}, User={mFtpUsername}");
                if (!string.IsNullOrEmpty(mFtpBasePath))
                    Console.WriteLine($"[FTP] Base path da rimuovere: {mFtpBasePath}");
            }
        }

        /// <summary>
        /// Scarica un file dal server FTP e lo salva nella cartella temporanea
        /// </summary>
        /// <param name="filePath">Path del file sul server remoto (es: C:\Files\document.pdf o /Files/document.pdf)</param>
        /// <param name="fu_id">ID del file upload (usato per generare il nome del file temporaneo)</param>
        /// <returns>FileInfo del file scaricato</returns>
        public FileInfo DownloadFile(string filePath, int fu_id)
        {
            try
            {
                // Converti il path Windows in path FTP
                // Da: C:\Files\document.pdf
                // A:  ftp://server/Files/document.pdf
                string ftpPath = ConvertToFtpPath(filePath);

                if (mDebug)
                    Console.WriteLine($"[FTP] Download file da: {ftpPath}");

                // Crea la richiesta FTP
                FtpWebRequest request = (FtpWebRequest)WebRequest.Create(ftpPath);
                request.Method = WebRequestMethods.Ftp.DownloadFile;
                request.Credentials = new NetworkCredential(mFtpUsername, mFtpPassword);
                request.UseBinary = true;
                request.KeepAlive = false;
                request.Timeout = 120000; // 2 minuti

                // Scarica il file
                using (FtpWebResponse response = (FtpWebResponse)request.GetResponse())
                using (Stream responseStream = response.GetResponseStream())
                {
                    // Determina l'estensione del file
                    string extension = Path.GetExtension(filePath);
                    if (string.IsNullOrEmpty(extension))
                        extension = ".tmp";

                    // Genera un nome file temporaneo unico
                    string tempFileName = $"fu_{fu_id}_{Guid.NewGuid()}{extension}";
                    string tempFilePath = Path.Combine(mTempFolder, tempFileName);

                    // Salva il file localmente
                    using (FileStream fileStream = File.Create(tempFilePath))
                    {
                        byte[] buffer = new byte[8192];
                        int bytesRead;
                        long totalBytes = 0;

                        while ((bytesRead = responseStream.Read(buffer, 0, buffer.Length)) > 0)
                        {
                            fileStream.Write(buffer, 0, bytesRead);
                            totalBytes += bytesRead;
                        }

                        if (mDebug)
                            Console.WriteLine($"[FTP] File scaricato con successo: {tempFilePath} ({totalBytes} bytes)");
                    }

                    return new FileInfo(tempFilePath);
                }
            }
            catch (WebException webEx)
            {
                FtpWebResponse response = (FtpWebResponse)webEx.Response;
                if (response != null)
                {
                    throw new Exception($"Errore FTP durante il download: {response.StatusCode} - {response.StatusDescription}", webEx);
                }
                else
                {
                    throw new Exception($"Errore durante il download del file via FTP: {webEx.Message}", webEx);
                }
            }
            catch (Exception ex)
            {
                throw new Exception($"Errore durante il download del file: {ex.Message}", ex);
            }
        }

        /// <summary>
        /// Converte un path in un URL FTP
        /// </summary>
        /// <param name="localPath">Path locale (es: C:\Files\document.pdf o /var/www/html/assets/temp/file.pdf)</param>
        /// <returns>URL FTP completo</returns>
        private string ConvertToFtpPath(string localPath)
        {
            if (string.IsNullOrEmpty(localPath))
                throw new ArgumentException("Path del file non può essere vuoto");

            string ftpPath = localPath;

            // Rimuovi il drive letter se presente (C:, D:, etc.)
            if (ftpPath.Length >= 2 && ftpPath[1] == ':')
            {
                ftpPath = ftpPath.Substring(2); // Rimuove "C:"
            }

            // Converti backslash in forward slash
            ftpPath = ftpPath.Replace('\\', '/');

            // Rimuovi il base path se configurato
            // Es: /var/www/html/assets/temp/file.pdf -> /temp/file.pdf
            if (!string.IsNullOrEmpty(mFtpBasePath))
            {
                if (ftpPath.StartsWith(mFtpBasePath, StringComparison.OrdinalIgnoreCase))
                {
                    ftpPath = ftpPath.Substring(mFtpBasePath.Length);
                    if (mDebug)
                        Console.WriteLine($"[FTP] Rimosso base path: {mFtpBasePath}");
                }
                else
                {
                    Console.WriteLine($"[FTP WARNING] Il path '{ftpPath}' non inizia con il base path '{mFtpBasePath}'");
                }
            }

            // Assicura che inizi con /
            if (!ftpPath.StartsWith("/"))
                ftpPath = "/" + ftpPath;

            // Combina con l'host FTP
            string fullFtpUrl = mFtpHost + ftpPath;

            if (mDebug)
                Console.WriteLine($"[FTP] Path convertito: {localPath} -> {fullFtpUrl}");

            return fullFtpUrl;
        }

        /// <summary>
        /// Elimina un file temporaneo
        /// </summary>
        public void DeleteTempFile(FileInfo file)
        {
            try
            {
                if (file != null && file.Exists)
                {
                    file.Delete();
                    if (mDebug)
                        Console.WriteLine($"[FTP] File temporaneo eliminato: {file.FullName}");
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[FTP ERROR] Errore durante l'eliminazione del file temporaneo: {ex.Message}");
            }
        }

        /// <summary>
        /// Pulisce tutti i file temporanei più vecchi di un certo numero di ore
        /// </summary>
        public void CleanupOldTempFiles(int olderThanHours = 24)
        {
            try
            {
                if (!Directory.Exists(mTempFolder))
                    return;

                DateTime threshold = DateTime.Now.AddHours(-olderThanHours);
                DirectoryInfo dir = new DirectoryInfo(mTempFolder);
                FileInfo[] files = dir.GetFiles();

                int deletedCount = 0;
                foreach (FileInfo file in files)
                {
                    if (file.LastWriteTime < threshold)
                    {
                        try
                        {
                            file.Delete();
                            deletedCount++;
                        }
                        catch (Exception ex)
                        {
                            Console.WriteLine($"[FTP ERROR] Errore durante l'eliminazione di {file.FullName}: {ex.Message}");
                        }
                    }
                }

                if (mDebug && deletedCount > 0)
                    Console.WriteLine($"[FTP] Pulizia completata: {deletedCount} file temporanei eliminati");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[FTP ERROR] Errore durante la pulizia dei file temporanei: {ex.Message}");
            }
        }
    }
}
