using System;
using System.Diagnostics;
using System.Timers;
using CefSharp;
using CefSharp.WinForms;
using TweetDuck.Core.Controls;
using Timer = System.Timers.Timer;

namespace TweetDuck.Core.Other.Management{
    sealed class MemoryUsageTracker : IDisposable{
        private const int IntervalMemoryCheck = 60000*30; // 30 minutes
        private const int IntervalCleanupAttempt = 60000*5; // 5 minutes

        private readonly string script;
        private readonly Timer timer;
        private FormBrowser owner;
        private IBrowser browser;

        private long threshold;
        private bool needsCleanup;

        public MemoryUsageTracker(string cleanupFunctionName){
            this.script = $"window.{cleanupFunctionName} && window.{cleanupFunctionName}()";

            this.timer = new Timer{ Interval = IntervalMemoryCheck };
            this.timer.Elapsed += timer_Elapsed;
        }

        public void Start(ChromiumWebBrowser control, int thresholdMB){
            Stop();

            this.owner = (FormBrowser)control.Parent; // TODO ugly
            this.browser = control.GetBrowser();
            this.threshold = thresholdMB*1024L*1024L;
            this.timer.SynchronizingObject = owner;
            this.timer.Start();
        }

        public void Stop(){
            timer.Stop();
            timer.SynchronizingObject = null;
            owner = null;
            browser = null;
            SetNeedsCleanup(false);
        }

        public void Dispose(){
            timer.SynchronizingObject = null;
            timer.Dispose();
            owner = null;
            browser = null;
        }

        private void SetNeedsCleanup(bool value){
            if (needsCleanup != value){
                needsCleanup = value;
                timer.Interval = value ? IntervalCleanupAttempt : IntervalMemoryCheck; // restarts timer
            }
        }

        private void timer_Elapsed(object sender, ElapsedEventArgs e){
            if (owner == null || browser == null){
                return;
            }
            
            if (needsCleanup){
                if (!owner.ContainsFocus){
                    using(IFrame frame = browser.MainFrame){
                        frame.EvaluateScriptAsync(script).ContinueWith(task => {
                            JavascriptResponse response = task.Result;

                            if (response.Success && (response.Result as bool? ?? false)){
                                SetNeedsCleanup(false);
                                owner.InvokeAsyncSafe(() => owner.TriggerAnalyticsEvent(Analytics.AnalyticsFile.Event.GCReload));
                            }
                        });
                    }
                }
            }
            else{
                try{
                    using(Process process = BrowserProcesses.FindProcess(browser)){
                        if (process?.PrivateMemorySize64 > threshold){
                            SetNeedsCleanup(true);
                        }
                    }
                }catch{
                    // ignore I guess?
                }
            }
        }
    }
}