#if DEBUG
// Uncomment to keep screenshot windows visible for debugging
// #define NO_HIDE_SCREENSHOTS

// Uncomment to generate screenshots of individual frames for at most 1 second
// #define GEN_SCREENSHOT_FRAMES
#endif

using System;
using System.Windows.Forms;
using TweetDuck.Core.Controls;
using TweetDuck.Plugins;

#if GEN_SCREENSHOT_FRAMES
using System.Drawing.Imaging;
using System.IO;
using TweetDuck.Core.Utils;
#endif

namespace TweetDuck.Core.Notification.Screenshot{
    sealed class TweetScreenshotManager : IDisposable{
        private readonly FormBrowser owner;
        private readonly PluginManager plugins;
        private readonly Timer timeout;
        private readonly Timer disposer;

        #if GEN_SCREENSHOT_FRAMES
        private readonly Timer debugger;
        private int frameCounter;

        public const int WaitFrames = 60;
        #else
        public const int WaitFrames = 5;
        #endif
        
        private FormNotificationScreenshotable screenshot;

        public TweetScreenshotManager(FormBrowser owner, PluginManager pluginManager){
            this.owner = owner;
            this.plugins = pluginManager;

            this.timeout = new Timer{ Interval = 8000 };
            this.timeout.Tick += timeout_Tick;

            this.disposer = new Timer{ Interval = 1 };
            this.disposer.Tick += disposer_Tick;

            #if GEN_SCREENSHOT_FRAMES
            this.debugger = new Timer{ Interval = 16 };
            this.debugger.Tick += debugger_Tick;
            #endif
        }

        private void timeout_Tick(object sender, EventArgs e){
            timeout.Stop();
            OnFinished();
        }

        private void disposer_Tick(object sender, EventArgs e){
            disposer.Stop();
            screenshot.Dispose();
            screenshot = null;
        }

        public void Trigger(string html, int width){
            if (screenshot != null){
                return;
            }

            screenshot = new FormNotificationScreenshotable(Callback, owner, plugins, html, width);
            screenshot.Show();
            timeout.Start();

            #if GEN_SCREENSHOT_FRAMES
            StartDebugger();
            #endif

            #if !NO_HIDE_SCREENSHOTS
            owner.IsWaiting = true;
            #endif
        }

        private void Callback(){
            if (!timeout.Enabled){
                return;
            }

            timeout.Stop();
            screenshot.TakeScreenshot();
            
            #if !NO_HIDE_SCREENSHOTS
            OnFinished();
            #else
            screenshot.MoveToVisibleLocation();
            screenshot.FormClosed += (sender, args) => disposer.Start();
            #endif
        }

        private void OnFinished(){
            #if GEN_SCREENSHOT_FRAMES
            debugger.Stop();
            #endif

            screenshot.Location = ControlExtensions.InvisibleLocation;
            owner.IsWaiting = false;
            disposer.Start();
        }

        public void Dispose(){
            #if GEN_SCREENSHOT_FRAMES
            debugger.Dispose();
            #endif

            timeout.Dispose();
            disposer.Dispose();
            screenshot?.Dispose();
        }

        #if GEN_SCREENSHOT_FRAMES
        private static readonly string DebugScreenshotPath = Path.Combine(Program.StoragePath, "TD_Screenshots");

        private void StartDebugger(){
            frameCounter = 0;

            try{
                Directory.Delete(DebugScreenshotPath, true);
                WindowsUtils.TrySleepUntil(() => !Directory.Exists(DebugScreenshotPath), 1000, 10);
            }catch(DirectoryNotFoundException){}
            
            Directory.CreateDirectory(DebugScreenshotPath);
            debugger.Start();
        }

        private void debugger_Tick(object sender, EventArgs e){
            if (frameCounter < 63 && screenshot.TakeScreenshot(true)){
                try{
                    Clipboard.GetImage()?.Save(Path.Combine(DebugScreenshotPath, "frame_"+(++frameCounter)+".png"), ImageFormat.Png);
                }catch{
                    System.Diagnostics.Debug.WriteLine("Failed generating frame "+frameCounter);
                }
            }
            else{
                debugger.Stop();
            }
        }
        #endif
    }
}