using System;
using System.Collections.Generic;
using System.IO;
using Microsoft.Extensions.Configuration;


namespace Sockeye.Util
{

    /// <summary>
    /// Contains config values from bootup
    /// </summary>
    internal static class ServerBootConfig
    {
        //############################################################################################################
        //STATIC HARD CODED COMPILE TIME DEFAULTS NOT SET THROUGH CONFIG
        internal const int FAILED_AUTH_DELAY = 3000;//ms
        internal const int JOB_OBJECT_HANDLE_BATCH_JOB_LOOP_DELAY = 200;//ms this delay is a temporary measure to ensure super big time consuming batch jobs don't use all server CPU resources
        internal const int JOB_PROGRESS_UPDATE_AND_CANCEL_CHECK_SECONDS = 5;//seconds between progress updates and checks for cancellation of long running jobs

        //UPLOAD LIMITS  1048576 = 1MiB for testing   10737420000 10737418240 10,737,418,240
        internal const long MAX_ATTACHMENT_UPLOAD_BYTES = 10737420000;//slight bit of overage as 10737418241=10GiB 
        internal const long MAX_LOGO_UPLOAD_BYTES = 512000;//500KiB limit
        internal const long MAX_IMPORT_FILE_UPLOAD_BYTES = 104857600;//100MiB limit
        internal const long MAX_REPORT_TEMPLATE_UPLOAD_BYTES = 15728640;//15MiB limit; currently the largest v7 export for a report template is 828kb, I'm guessing 15mb is more than enough
        internal const long MAX_TRANSLATION_UPLOAD_BYTES = 15728640;//15MiB limit; currently export file is 200kb * 50 maximum at a time = 15mb
        //############################################################################################################

          //############################
        //MIGRATING FLAG INTERNAL ONLY
        //used to speed up rockfish migration with bypasses to notification processing
        internal static bool MIGRATING { get; set; }
        //############################

        //Diagnostic static values used during development, may not be related to config at all, this is just a convenient class to put them in
#if (DEBUG)
        internal static List<string> TranslationKeysRequested { get; set; }

#endif


        //CONTENTROOTPATH
        //** Not intended for end users but required in release mode
        internal static string SOCKEYE_CONTENT_ROOT_PATH { get; set; } //Note: set in startup.cs, not in program.cs as it requires startup IHostingEnvironment


        //LANGUAGE / Translation
        internal static string SOCKEYE_DEFAULT_TRANSLATION { get; set; }
        //** Not intended for end users
        internal static long SOCKEYE_DEFAULT_TRANSLATION_ID { get; set; } //internal setting set at boot by TranslationBiz::ValidateTranslations

        //API
        internal static string SOCKEYE_JWT_SECRET { get; set; }
        internal static string SOCKEYE_USE_URLS { get; set; }
        internal static int SOCKEYE_REPORT_RENDERING_TIMEOUT { get; set; }


        //DATABASE
        internal static string SOCKEYE_DB_CONNECTION { get; set; }
        //** Not intended for end users
        internal static bool SOCKEYE_PERMANENTLY_ERASE_DATABASE { get; set; }

       
        //FILE FOLDERS
        internal static string SOCKEYE_ATTACHMENT_FILES_PATH { get; set; }
        internal static string SOCKEYE_BACKUP_FILES_PATH { get; set; }
        internal static string SOCKEYE_TEMP_FILES_PATH { get; set; }

        //BACKUP PG_DUMP PATH (IF NOT IN PATH ALREADY)
        internal static string SOCKEYE_BACKUP_PG_DUMP_PATH { get; set; }

        //REPORT RENDERING BROWSER PATH (if not set then will attempt to auto-download on first render)
        internal static string SOCKEYE_REPORT_RENDER_BROWSER_PATH { get; set; }
        //REPORT RENDERING BROWSER PARAMS 
        internal static string SOCKEYE_REPORT_RENDER_BROWSER_PARAMS { get; set; }


        //LOGGING
        internal static string SOCKEYE_LOG_PATH { get; set; }
        internal static string SOCKEYE_LOG_LEVEL { get; set; }
        internal static bool SOCKEYE_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG { get; set; }

        //SECURITY
        internal static string SOCKEYE_SET_SUPERUSER_PW { get; set; }

        //HELPFUL INFORMATION FOR DIAGNOSTICS
        internal static Dictionary<string, string> BOOT_DIAGNOSTIC_INFO { get; set; } = new Dictionary<string, string>();
        internal static Dictionary<string, string> DBSERVER_DIAGNOSTIC_INFO { get; set; } = new Dictionary<string, string>();


        /// <summary>
        /// Populate the config from the configuration found at boot
        /// called by program.cs
        /// </summary>
        /// <param name="config"></param>
        internal static void SetConfiguration(IConfigurationRoot config)
        {

#if (DEBUG)
            TranslationKeysRequested = new List<string>();
#endif

            bool? bTemp = null;

            #region SERVER BASICS


            //LANGUAGE
            //TranslationBiz will validate this later at boot pfc and ensure a sane default is set (English)
            SOCKEYE_DEFAULT_TRANSLATION = config.GetValue<string>("SOCKEYE_DEFAULT_TRANSLATION");
            SOCKEYE_DEFAULT_TRANSLATION = string.IsNullOrWhiteSpace(SOCKEYE_DEFAULT_TRANSLATION) ? "en" : SOCKEYE_DEFAULT_TRANSLATION;
            string lowTranslation = SOCKEYE_DEFAULT_TRANSLATION.ToLowerInvariant();
            switch (lowTranslation)
            {
                case "en":
                case "english":
                    SOCKEYE_DEFAULT_TRANSLATION = "en";
                    break;
                case "de":
                case "deutsch":
                case "german":
                    SOCKEYE_DEFAULT_TRANSLATION = "de";
                    break;
                case "es":
                case "español":
                case "spanish":
                    SOCKEYE_DEFAULT_TRANSLATION = "es";
                    break;
                case "fr":
                case "français":
                case "french":
                    SOCKEYE_DEFAULT_TRANSLATION = "fr";
                    break;
                default:
                    SOCKEYE_DEFAULT_TRANSLATION = "en";
                    break;
            }




            //LOGLEVEL
            SOCKEYE_LOG_LEVEL = config.GetValue<string>("SOCKEYE_LOG_LEVEL");
            SOCKEYE_LOG_LEVEL = string.IsNullOrWhiteSpace(SOCKEYE_LOG_LEVEL) ? "Info" : SOCKEYE_LOG_LEVEL;

            //LOGGING DIAGNOSTIC LOG
            bTemp = config.GetValue<bool?>("SOCKEYE_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG");
            SOCKEYE_LOG_ENABLE_LOGGER_DIAGNOSTIC_LOG = (null == bTemp) ? false : (bool)bTemp;

            //PORT / API
            SOCKEYE_USE_URLS = config.GetValue<string>("SOCKEYE_USE_URLS");
            SOCKEYE_USE_URLS = string.IsNullOrWhiteSpace(SOCKEYE_USE_URLS) ? "http://*:7575" : SOCKEYE_USE_URLS;

            SOCKEYE_JWT_SECRET = config.GetValue<string>("SOCKEYE_JWT_SECRET");

            //backdoor back door password superuser reset
            SOCKEYE_SET_SUPERUSER_PW = config.GetValue<string>("SOCKEYE_SET_SUPERUSER_PW");

            //REPORT RENDERING 

            //RENDER ENGINE PATH 
            SOCKEYE_REPORT_RENDER_BROWSER_PATH = ActualFullPath(config.GetValue<string>("SOCKEYE_REPORT_RENDER_BROWSER_PATH"));

            //RENDER ENGINE PARAMS
            SOCKEYE_REPORT_RENDER_BROWSER_PARAMS = config.GetValue<string>("SOCKEYE_REPORT_RENDER_BROWSER_PARAMS");

            //PROCESS CONTROL
            int? nTemp = config.GetValue<int?>("SOCKEYE_REPORT_RENDERING_TIMEOUT");
            SOCKEYE_REPORT_RENDERING_TIMEOUT = (null == nTemp) ? 5 : (int)nTemp;//default
            if (SOCKEYE_REPORT_RENDERING_TIMEOUT < 1) SOCKEYE_REPORT_RENDERING_TIMEOUT = 1; //one minute minimum timeout



            //DB
            SOCKEYE_DB_CONNECTION = config.GetValue<string>("SOCKEYE_DB_CONNECTION");
            bTemp = config.GetValue<bool?>("SOCKEYE_PERMANENTLY_ERASE_DATABASE");
            SOCKEYE_PERMANENTLY_ERASE_DATABASE = (null == bTemp) ? false : (bool)bTemp;

         


            //FOLDERS
            string DataFolderPath = ActualFullPath(config.GetValue<string>("SOCKEYE_DATA_PATH"));
            string LogPath = ActualFullPath(config.GetValue<string>("SOCKEYE_LOG_PATH"));
            string AttachmentFilesPath = ActualFullPath(config.GetValue<string>("SOCKEYE_ATTACHMENT_FILES_PATH"));
            string BackupFilesPath = ActualFullPath(config.GetValue<string>("SOCKEYE_BACKUP_FILES_PATH"));
            string TempFilesPath = ActualFullPath(config.GetValue<string>("SOCKEYE_TEMP_FILES_PATH"));
            SOCKEYE_BACKUP_PG_DUMP_PATH = ActualFullPath(config.GetValue<string>("SOCKEYE_BACKUP_PG_DUMP_PATH"));

            if (string.IsNullOrWhiteSpace(DataFolderPath))
            {
                //In this case *must* have paths for *everything* specified
                if (string.IsNullOrWhiteSpace(LogPath))
                    throw new System.ArgumentNullException("SOCKEYE_LOG_PATH configuration setting missing and required");
                if (string.IsNullOrWhiteSpace(AttachmentFilesPath))
                    throw new System.ArgumentNullException("SOCKEYE_ATTACHMENT_FILES_PATH configuration setting missing and required");
                if (string.IsNullOrWhiteSpace(BackupFilesPath))
                    throw new System.ArgumentNullException("SOCKEYE_BACKUP_FILES_PATH configuration setting missing and required");
                if (string.IsNullOrWhiteSpace(TempFilesPath))
                    throw new System.ArgumentNullException("SOCKEYE_TEMP_FILES_PATH configuration setting missing and required");

            }

            //set paths
            SOCKEYE_LOG_PATH = (string.IsNullOrWhiteSpace(LogPath)) ? Path.Combine(DataFolderPath, "logs") : LogPath;
            SOCKEYE_ATTACHMENT_FILES_PATH = (string.IsNullOrWhiteSpace(AttachmentFilesPath)) ? Path.Combine(DataFolderPath, "attachments") : AttachmentFilesPath;
            SOCKEYE_BACKUP_FILES_PATH = (string.IsNullOrWhiteSpace(BackupFilesPath)) ? Path.Combine(DataFolderPath, "backups") : BackupFilesPath;
            SOCKEYE_TEMP_FILES_PATH = (string.IsNullOrWhiteSpace(TempFilesPath)) ? Path.Combine(DataFolderPath, "temp") : TempFilesPath;


            #endregion server BASICS

        }


        internal static string ActualFullPath(string p)
        {
            if (string.IsNullOrWhiteSpace(p))
                return string.Empty;
            return Path.GetFullPath(FileUtil.StringPathDecodeEnvironmentVariables(p));
        }

        //Fetch first url from list of urls (used by generator)
        internal static string FirstOfSockeyeUseUrls
        {
            get
            {
                if (string.IsNullOrWhiteSpace(SOCKEYE_USE_URLS))
                { return null; }

                if (!SOCKEYE_USE_URLS.Contains(";"))
                {
                    return SOCKEYE_USE_URLS.Replace("*", "localhost");
                }
                var s = SOCKEYE_USE_URLS.Split(';');
                return s[0].Replace("*", "localhost");

            }
        }





    }//eoc


}//eons