using System;
using Pixiview.UI.Theme;
using Pixiview.Utils;
using Xamarin.Essentials;
using Xamarin.Forms;

namespace Pixiview.UI
{
    public class AdaptedPage : ContentPage
    {
        public static readonly BindableProperty PageTopMarginProperty = BindableProperty.Create(
            nameof(PageTopMargin), typeof(Thickness), typeof(AdaptedPage));
        public static readonly BindableProperty PanelTopMarginProperty = BindableProperty.Create(
            nameof(PanelTopMargin), typeof(Thickness), typeof(AdaptedPage));

        public Thickness PageTopMargin
        {
            get => (Thickness)GetValue(PageTopMarginProperty);
            protected set => SetValue(PageTopMarginProperty, value);
        }
        public Thickness PanelTopMargin
        {
            get => (Thickness)GetValue(PanelTopMarginProperty);
            protected set => SetValue(PanelTopMarginProperty, value);
        }

        public event EventHandler Load;
        public event EventHandler Unload;

        protected static readonly bool isPhone = DeviceInfo.Idiom == DeviceIdiom.Phone;

        public AdaptedPage()
        {
            SetDynamicResource(Screen.StatusBarStyleProperty, ThemeBase.StatusBarStyle);
            Shell.SetNavBarHasShadow(this, true);
        }

        public virtual void OnLoad()
        {
            Load?.Invoke(this, EventArgs.Empty);
        }

        public virtual void OnUnload()
        {
            Unload?.Invoke(this, EventArgs.Empty);
        }

#if __IOS__
        public virtual void OnOrientationChanged(bool landscape)
        {
            var oldMargin = PageTopMargin;
            var oldPanelMargin = PanelTopMargin;
            Thickness newMargin;
            Thickness newPanelMargin;
            if (StyleDefinition.IsFullscreenDevice)
            {
                newMargin = landscape ?
                    AppShell.NavigationBarOffset :
                    AppShell.TotalBarOffset;
                newPanelMargin = landscape ?
                    AppShell.HalfNavigationBarOffset :
                    AppShell.NavigationBarOffset;
            }
            else if (isPhone)
            {
                newMargin = landscape ?
                    StyleDefinition.TopOffset32 :
                    AppShell.TotalBarOffset;
                newPanelMargin = landscape ?
                    StyleDefinition.TopOffset16 :
                    StyleDefinition.TopOffset32;
            }
            else
            {
                // iPad
                newMargin = AppShell.TotalBarOffset;
                newPanelMargin = StyleDefinition.TopOffset37;
            }
            if (oldMargin != newMargin)
            {
                PageTopMargin = newMargin;
                OnPageTopMarginChanged(oldMargin, newMargin);
            }
            if (oldPanelMargin != newPanelMargin)
            {
                PanelTopMargin = newPanelMargin;
            }
        }

        protected virtual void OnPageTopMarginChanged(Thickness old, Thickness @new) { }

        protected override void OnSizeAllocated(double width, double height)
        {
            base.OnSizeAllocated(width, height);
            OnOrientationChanged(width > height);
        }

        protected void AnimateToMargin(View element, Thickness margin, bool animate = true)
        {
            var m = margin;
            var start = element.Margin.Top - m.Top;
#if DEBUG
            if (start != 0)
            {
                App.DebugPrint($"{element.GetType()}, margin-top from {element.Margin.Top} to {margin.Top}");
            }
#endif
            element.Margin = m;
            if (start > 0 && animate)
            {
                ViewExtensions.CancelAnimations(element);
                element.Animate("margin", top =>
                {
                    element.TranslationY = top;
                },
                start, 0,
#if DEBUG
                length: 500,
#else
                length: 300,
#endif
                easing: Easing.SinInOut,
                finished: (v, r) =>
                {
                    element.TranslationY = 0;
                });
            }
        }
#endif

        protected void Start(Action action)
        {
            if (Tap.IsBusy)
            {
#if LOG
                App.DebugPrint("gesture recognizer is now busy...");
#endif
                return;
            }
            using (Tap.Start())
            {
                action();
            }
        }

        private class Tap : IDisposable
        {
            public static bool IsBusy
            {
                get
                {
                    lock (sync)
                    {
                        return _instance?.isBusy == true;
                    }
                }
            }

            private static readonly object sync = new object();
            private static readonly Tap _instance = new Tap();

            private Tap() { }

            public static Tap Start()
            {
                lock (sync)
                {
                    _instance.isBusy = true;
                }
                return _instance;
            }

            private bool isBusy = false;

            public void Dispose()
            {
                isBusy = false;
            }
        }
    }

    public class ThicknessEventArgs : EventArgs
    {
        public Thickness OldMargin { get; set; }
        public Thickness NewMargin { get; set; }
    }
}
