using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Web;
using System.Web.Http;
using System.Web.Mvc;
using System.Web.Optimization;
using System.Web.Routing;
using System.Threading;

using C4IT.Logging;
using C4IT.Security;
using C4IT.FASD.Security;
using C4IT.DataHistoryProvider;
using C4IT.XML;
using C4IT.FASD.Licensing;
using static C4IT.Logging.cLogManager;
using FasdWebService;
using System.IO;
using System.Text;
using System.Web.UI;
using System.Threading.Tasks;

namespace F4SDwebService
{
    public class WebApiApplication : System.Web.HttpApplication
    {
        public static cDataHistoryCollector Collector = null;

        public static bool notConfigured = false;

        static public WebApiApplication Instance = null;

        static public bool Debug_apiTiming = false;

        static private string ApiTimingLog = null;
        static private object ApiTimingLogSync = new object();

        private System.Timers.Timer LicenceCheck;
        private System.Timers.Timer SessionCheck;
        private System.Timers.Timer CaseCheck;
        protected async void Application_Start()
        {
            // initialize the logging
            var assembly = Assembly.GetExecutingAssembly();
            var _lm = cLogManagerFile.CreateInstance(true, SubFolder: "Logs", A: assembly, DebugFlags: new List<string>() { "Performance", "ApiTiming" });
            if (_lm.CheckDebugFlag("Performance"))
            {
                var FN = _lm.GetLogFileName();
                var FN2 = Path.Combine(Path.GetDirectoryName(FN), Path.GetFileNameWithoutExtension(FN) + "-Perf.log");
                cPerformanceLogger.SetManager(cLogManagerFile.Create(FN2));
            }

            Debug_apiTiming = _lm.CheckDebugFlag("ApiTiming");
            DataHistorySqlHelper.LogSql = Debug_apiTiming;
            if (Debug_apiTiming)
                DataHistorySqlHelper.SqlLogFileName = DataHistorySqlHelper.GetSqlLogFileName();

            cLogManager.DefaultLogger.LogAssemblyInfo(assembly);


            MethodBase CM = null; if (cLogManager.DefaultLogger.IsDebug) { CM = MethodBase.GetCurrentMethod(); LogMethodBegin(CM); }
            try
            {
                Instance = this;
                cF4SDLicense.CheckLicense(null, null);

                var lstLicenseLog = cF4SDLicense.LogLicenseState();
                cLogManager.DefaultLogger.LogList(LogLevels.Info, lstLicenseLog);

                LicenceCheck = new System.Timers.Timer(60.0 * 60 * 1000);
                LicenceCheck.Elapsed += cF4SDLicense.CheckLicense;
                LicenceCheck.Start();

                // initialize the default encryption
                FasdSecurity.Init();

                AreaRegistration.RegisterAllAreas();
                GlobalConfiguration.Configure(WebApiConfig.Register);
                FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
                RouteConfig.RegisterRoutes(RouteTable.Routes);
                BundleConfig.RegisterBundles(BundleTable.Bundles);

                var OTPWs = new Dictionary<string, cOneTimePW>() {
                    {"OneTimePw",  new cOneTimePW("OneTimePw", cSecurePassword.Instance) }
                };

                if (!(cF4SDLicense.Instance?.IsValid is true))
                    return;

                var _requestInfo = new cF4sdWebRequestInfo("Application_Start", null);

                cXmlParser.XsdAssembly = Assembly.GetExecutingAssembly();
                var Collector = new cDataHistoryCollector(autoConnectionCheck: true, _requestInfo, 0);

                lock (Collector.SessionValues)
                    Collector.SessionValues.Clear();

                Collector.CaseValues.Clear();

                var IsLoaded = await Collector.LoadConfigurationAsync(false, false, CancellationToken.None, _requestInfo, 0, ExecutingAssembly: Assembly.GetExecutingAssembly());
                if (!IsLoaded)
                    return;

                WebApiConfig.authenticationHandler.Collector = Collector;
                WebApiConfig.authenticationHandler.OTPWs = OTPWs;

                cConfigCache.Initialize();

                IsLoaded = await Collector.ValidateHistoryDatabasesAsync(true, CancellationToken.None, _requestInfo, 0);
                if (Collector.ServerStatus == C4IT.FASD.Base.enumWebServerStatus.notConfigured)
                    notConfigured = true;
                if (!IsLoaded)
                    return;

                await Collector.ValidateF4SDAnalyticsDBAsync(_requestInfo, 1, CancellationToken.None);
                if (Collector.F4SDAnalyticsValid)
                {
                    SessionCheck = new System.Timers.Timer(60 * 1000 * Collector.F4SDAnalyticsDb.SessionCheckInterval);
                    SessionCheck.Elapsed += Collector.CheckSessionsAsync;
                    SessionCheck.Start();

                    CaseCheck = new System.Timers.Timer(60 * 1000 * Collector.F4SDAnalyticsDb.CaseCheckInterval);
                    CaseCheck.Elapsed += Collector.CheckCasesAsync;
                    CaseCheck.Start();
                }
                if (IsLoaded && Collector.IsValid)
                    WebApiApplication.Collector = Collector;

                if (Collector.M42WpmCollector != null)
                    await Collector.M42WpmCollector.ValidateConnectionAsync(true, CancellationToken.None);

                if (Collector.CitrixCollector != null)
                    await Collector.CitrixCollector.ValidateConnectionsAsync(CancellationToken.None);

                Collector.ServerStatus = C4IT.FASD.Base.enumWebServerStatus.active;
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                if (CM != null) LogMethodEnd(CM);
            }

        }

        public static void SaveApiTimingEntry(string ApiName, string ApiId, DateTime timeStart, int error)
        {
            if (!Debug_apiTiming)
                return;

            Task.Factory.StartNew(() =>
            {
                try
                {
                    var end = DateTime.UtcNow;
                    var duration = (end - timeStart).TotalMilliseconds;
                    var _strStart = timeStart.ToString("yyyy-MM-dd-HH-mm-ss-FFFFF");
                    var _strEnd = end.ToString("yyyy-MM-dd-HH-mm-ss-FFFFF");

                    lock (ApiTimingLogSync)
                    {

                        if (ApiTimingLog == null)
                        {
                            if (!(cLogManager.Instance is cLogManagerFile lf))
                                return;

                            if (string.IsNullOrEmpty(lf.LogFolder))
                                return;

                            var _fn = Path.GetFileNameWithoutExtension(lf.GetLogFileName());
                            ApiTimingLog = Path.Combine(lf.LogFolder, _fn + "-ApiTiming.log");
                        }

                        var _line = string.Format("{0}\t{1}\t{2}\t{3}\t{4}\t{5}\r\n", _strStart, _strEnd, ApiName, duration, error, ApiId);
                        System.IO.File.AppendAllText(ApiTimingLog, _line, Encoding.UTF8);
                    }
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            });
        }
    }

}
