using System;
using System.Drawing;
using System.Drawing.Imaging;
using System.Windows.Forms;
using CefSharp;
using TweetDuck.Browser.Adapters;
using TweetDuck.Controls;
using TweetDuck.Dialogs;
using TweetDuck.Utils;
using TweetLib.Core.Data;
using TweetLib.Core.Features.Notifications;
using TweetLib.Core.Features.Plugins;

namespace TweetDuck.Browser.Notification.Screenshot{
    sealed class FormNotificationScreenshotable : FormNotificationBase{
        protected override bool CanDragWindow => false;

        private readonly PluginManager plugins;
        private int height;

        public FormNotificationScreenshotable(Action callback, FormBrowser owner, PluginManager pluginManager, string html, int width) : base(owner, false){
            this.plugins = pluginManager;

            int realWidth = BrowserUtils.Scale(width, DpiScale);

            browser.RegisterJsBridge("$TD_NotificationScreenshot", new ScreenshotBridge(this, SetScreenshotHeight, callback));

            browser.LoadingStateChanged += (sender, args) => {
                if (args.IsLoading){
                    return;
                }

                string script = Program.Resources.LoadSilent("screenshot.js");
                
                if (script == null){
                    this.InvokeAsyncSafe(callback);
                    return;
                }

                using IFrame frame = args.Browser.MainFrame;
                CefScriptExecutor.RunScript(frame, script.Replace("{width}", realWidth.ToString()).Replace("{frames}", TweetScreenshotManager.WaitFrames.ToString()), "gen:screenshot");
            };
            
            SetNotificationSize(realWidth, 1024);
            LoadTweet(new DesktopNotification(string.Empty, string.Empty, string.Empty, html, 0, string.Empty, string.Empty));
        }

        protected override string GetTweetHTML(DesktopNotification tweet){
            string html = tweet.GenerateHtml("td-screenshot", HeadLayout, Config.CustomNotificationCSS);

            foreach(InjectedHTML injection in plugins.NotificationInjections){
                html = injection.InjectInto(html);
            }

            return html;
        }

        private void SetScreenshotHeight(int browserHeight){
            this.height = BrowserUtils.Scale(browserHeight, SizeScale);
        }

        public bool TakeScreenshot(bool ignoreHeightError = false){
            if (!ignoreHeightError){
                if (height == 0){
                    FormMessage.Error("Screenshot Failed", "Could not detect screenshot size.", FormMessage.OK);
                    return false;
                }
                else if (height > ClientSize.Height){
                    FormMessage.Error("Screenshot Failed", $"Screenshot is too large: {height}px > {ClientSize.Height}px", FormMessage.OK);
                    return false;
                }
            }

            if (!WindowsUtils.IsAeroEnabled){
                MoveToVisibleLocation(); // TODO make this look nicer I guess
            }
            
            IntPtr context = NativeMethods.GetDC(this.Handle);

            if (context == IntPtr.Zero){
                FormMessage.Error("Screenshot Failed", "Could not retrieve a graphics context handle for the notification window to take the screenshot.", FormMessage.OK);
                return false;
            }
            else{
                using Bitmap bmp = new Bitmap(ClientSize.Width, Math.Max(1, height), PixelFormat.Format32bppRgb);

                try{
                    NativeMethods.RenderSourceIntoBitmap(context, bmp);
                }finally{
                    NativeMethods.ReleaseDC(this.Handle, context);
                }

                Clipboard.SetImage(bmp);
                return true;
            }
        }
    }
}