using System.Drawing;
using System.Windows.Forms;
using CefSharp.WinForms;
using TweetDuck.Browser.Data;
using TweetDuck.Browser.Handling;
using TweetDuck.Browser.Handling.General;
using TweetDuck.Configuration;
using TweetDuck.Controls;
using TweetDuck.Management.Analytics;
using TweetDuck.Utils;
using TweetLib.Core.Features.Notifications;
using TweetLib.Core.Features.Twitter;

namespace TweetDuck.Browser.Notification{
    abstract partial class FormNotificationBase : Form, AnalyticsFile.IProvider{
        public static readonly ResourceLink AppLogo = new ResourceLink("https://ton.twimg.com/tduck/avatar", ResourceHandlers.ForBytes(Properties.Resources.avatar, "image/png"));

        protected const string BlankURL = TwitterUrls.TweetDeck + "/?blank";

        public static string FontSize = null;
        public static string HeadLayout = null;

        protected static UserConfig Config => Program.Config.User;
        
        protected static int FontSizeLevel{
            get => FontSize switch{
                "largest"  => 4,
                "large"    => 3,
                "small"    => 1,
                "smallest" => 0,
                _          => 2
            };
        }

        protected virtual Point PrimaryLocation{
            get{
                Screen screen;

                if (Config.NotificationDisplay > 0 && Config.NotificationDisplay <= Screen.AllScreens.Length){
                    screen = Screen.AllScreens[Config.NotificationDisplay - 1];
                }
                else{
                    screen = Screen.FromControl(owner);
                }
            
                int edgeDist = Config.NotificationEdgeDistance;

                switch(Config.NotificationPosition){
                    case DesktopNotification.Position.TopLeft:
                        return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + edgeDist);

                    case DesktopNotification.Position.TopRight:
                        return new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + edgeDist);

                    case DesktopNotification.Position.BottomLeft:
                        return new Point(screen.WorkingArea.X + edgeDist, screen.WorkingArea.Y + screen.WorkingArea.Height - edgeDist - Height);

                    case DesktopNotification.Position.BottomRight:
                        return new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + screen.WorkingArea.Height - edgeDist - Height);

                    case DesktopNotification.Position.Custom:
                        if (!Config.IsCustomNotificationPositionSet){
                            Config.CustomNotificationPosition = new Point(screen.WorkingArea.X + screen.WorkingArea.Width - edgeDist - Width, screen.WorkingArea.Y + edgeDist);
                            Config.Save();
                        }

                        return Config.CustomNotificationPosition;
                }

                return Location;
            }
        }

        protected bool IsNotificationVisible => Location != ControlExtensions.InvisibleLocation;
        protected virtual bool CanDragWindow => true;

        public new Point Location{
            get{
                return base.Location;
            }

            set{
                Visible = (base.Location = value) != ControlExtensions.InvisibleLocation;
                FormBorderStyle = NotificationBorderStyle;
            }
        }

        protected virtual FormBorderStyle NotificationBorderStyle{
            get{
                if (WindowsUtils.ShouldAvoidToolWindow && Visible){ // Visible = workaround for alt+tab
                    return FormBorderStyle.FixedSingle;
                }
                else{
                    return FormBorderStyle.FixedToolWindow;
                }
            }
        }

        public AnalyticsFile AnalyticsFile => owner.AnalyticsFile;
        
        protected override bool ShowWithoutActivation => true;
        
        protected float DpiScale { get; }
        protected double SizeScale => DpiScale * Config.ZoomLevel / 100.0;

        protected readonly FormBrowser owner;

        #pragma warning disable IDE0069 // Disposable fields should be disposed
        protected readonly ChromiumWebBrowser browser;
        #pragma warning restore IDE0069 // Disposable fields should be disposed

        private readonly ResourceHandlerNotification resourceHandler = new ResourceHandlerNotification();

        private DesktopNotification currentNotification;
        private int pauseCounter;
        
        public string CurrentTweetUrl => currentNotification?.TweetUrl;
        public string CurrentQuoteUrl => currentNotification?.QuoteUrl;

        public bool CanViewDetail => currentNotification != null && !string.IsNullOrEmpty(currentNotification.ColumnId) && !string.IsNullOrEmpty(currentNotification.ChirpId);

        protected bool IsPaused => pauseCounter > 0;
        protected bool IsCursorOverBrowser => browser.Bounds.Contains(PointToClient(Cursor.Position));
        
        public bool FreezeTimer { get; set; }
        public bool ContextMenuOpen { get; set; }

        protected FormNotificationBase(FormBrowser owner, bool enableContextMenu){
            InitializeComponent();

            this.owner = owner;
            this.owner.FormClosed += owner_FormClosed;
            
            var resourceRequestHandler = new ResourceRequestHandlerBase();
            var resourceHandlers = resourceRequestHandler.ResourceHandlers;

            resourceHandlers.Register(BlankURL, ResourceHandlers.ForString(string.Empty));
            resourceHandlers.Register(TwitterUrls.TweetDeck, () => this.resourceHandler);
            resourceHandlers.Register(AppLogo);

            this.browser = new ChromiumWebBrowser(BlankURL){
                MenuHandler = new ContextMenuNotification(this, enableContextMenu),
                JsDialogHandler = new JavaScriptDialogHandler(),
                LifeSpanHandler = new LifeSpanHandler(),
                RequestHandler = new RequestHandlerBase(false),
                ResourceRequestHandlerFactory = resourceRequestHandler.SelfFactory
            };

            this.browser.Dock = DockStyle.None;
            this.browser.ClientSize = ClientSize;
            this.browser.SetupZoomEvents();

            Controls.Add(browser);

            Disposed += (sender, args) => {
                this.owner.FormClosed -= owner_FormClosed;
                this.browser.Dispose();
            };

            DpiScale = this.GetDPIScale();

            // ReSharper disable once VirtualMemberCallInContructor
            UpdateTitle();
        }

        protected override void Dispose(bool disposing){
            if (disposing){
                components?.Dispose();
                resourceHandler.Dispose();
            }

            base.Dispose(disposing);
        }

        protected override void WndProc(ref Message m){
            if (m.Msg == 0x0112 && (m.WParam.ToInt32() & 0xFFF0) == 0xF010 && !CanDragWindow){ // WM_SYSCOMMAND, SC_MOVE
                return;
            }

            base.WndProc(ref m);
        }

        // event handlers

        private void owner_FormClosed(object sender, FormClosedEventArgs e){
            Close();
        }

        // notification methods

        public virtual void HideNotification(){
            browser.Load(BlankURL);
            DisplayTooltip(null);

            Location = ControlExtensions.InvisibleLocation;
            currentNotification = null;
        }

        public virtual void FinishCurrentNotification(){}

        public virtual void PauseNotification(){
            if (pauseCounter++ == 0 && IsNotificationVisible){
                Location = ControlExtensions.InvisibleLocation;
            }
        }

        public virtual void ResumeNotification(){
            if (pauseCounter > 0){
                --pauseCounter;
            }
        }

        protected abstract string GetTweetHTML(DesktopNotification tweet);

        protected virtual void LoadTweet(DesktopNotification tweet){
            currentNotification = tweet;
            resourceHandler.SetHTML(GetTweetHTML(tweet));

            browser.Load(TwitterUrls.TweetDeck);
            DisplayTooltip(null);
        }

        protected virtual void SetNotificationSize(int width, int height){
            browser.ClientSize = ClientSize = new Size(BrowserUtils.Scale(width, SizeScale), BrowserUtils.Scale(height, SizeScale));
        }

        protected virtual void UpdateTitle(){
            string title = currentNotification?.ColumnTitle;
            Text = string.IsNullOrEmpty(title) || !Config.DisplayNotificationColumn ? Program.BrandName : $"{Program.BrandName} - {title}";
        }

        public void ShowTweetDetail(){
            if (currentNotification != null){
                owner.ShowTweetDetail(currentNotification.ColumnId, currentNotification.ChirpId, currentNotification.TweetUrl);
            }
        }

        public void MoveToVisibleLocation(){
            bool needsReactivating = Location == ControlExtensions.InvisibleLocation;
            Location = PrimaryLocation;

            if (needsReactivating){
                NativeMethods.SetFormPos(this, NativeMethods.HWND_TOPMOST, NativeMethods.SWP_NOACTIVATE);
            }
        }

        public void DisplayTooltip(string text){
            if (string.IsNullOrEmpty(text)){
                toolTip.Hide(this);
            }
            else{
                Point position = PointToClient(Cursor.Position);
                position.Offset(20, 5);
                toolTip.Show(text, this, position);
            }
        }
    }
}