using C4IT.FASD.Base;
using FasdDesktopUi.Basics;
using FasdDesktopUi.Basics.Models;
using System;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using WinForms = System.Windows.Forms;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Pages.TicketCompletion
{
    public partial class TicketCompletion : Window, IBlurInvoker, INotifyPropertyChanged
    {
        private const double MinWindowHeightDip = 220d;
        private const double WindowWorkingAreaMarginDip = 12d;
        private const double DialogNonContentReserveDip = 180d;
        private bool isUpdatingDialogBounds;
        private bool isCanceled = false;

        private bool _WaitForClosing = false;
        public bool WaitForClosing
        {
            get { return _WaitForClosing; }
            set
            {
                if (value != _WaitForClosing)
                {
                    _WaitForClosing = value;
                    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs("WaitForClosing"));
                }
            }
        }

        private readonly cSupportCaseDataProvider _dataProvider;

        public event PropertyChangedEventHandler PropertyChanged;

        private TicketCompletion(cSupportCaseDataProvider dataProvider)
        {
            InitializeComponent();
            _dataProvider = dataProvider;
            CloseCaseDialogUc.DataProvider = _dataProvider;
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);

            cFocusInvoker.GotFocus += ElementGotFocus;
            cFocusInvoker.LostFocus += ElementLostFocus;
            SizeChanged += TicketCompletion_SizeChanged;
            Loaded += TicketCompletion_Loaded;
        }

        protected override void OnSourceInitialized(EventArgs e)
        {
            base.OnSourceInitialized(e);
            UpdateDialogMaxHeightToScreen();
        }

        protected override void OnLocationChanged(EventArgs e)
        {
            base.OnLocationChanged(e);
            UpdateDialogMaxHeightToScreen();
        }

        private void TicketCompletion_Loaded(object sender, RoutedEventArgs e) => UpdateDialogMaxHeightToScreen();

        private void TicketCompletion_SizeChanged(object sender, SizeChangedEventArgs e) => UpdateDialogMaxHeightToScreen();

        #region ClosingBusy

        public bool IsClosingBusy
        {
            get { return (bool)GetValue(IsClosingBusyProperty); }
            set { SetValue(IsClosingBusyProperty, value); }
        }

        public static readonly DependencyProperty IsClosingBusyProperty =
            DependencyProperty.Register("IsClosingBusy", typeof(bool), typeof(TicketCompletion), new PropertyMetadata(false));

        #endregion

        public static bool? Show(cSupportCaseDataProvider DataProvider, Window Owner)
        {
            try
            {
                var existingMessageBox = Application.Current.Windows.Cast<Window>().FirstOrDefault(window => window is TicketCompletion);
                if (existingMessageBox != null)
                {
                    existingMessageBox.Show();
                    return null;
                }

                TicketCompletion ticketCompletion = new TicketCompletion(DataProvider);

                if (Owner != null)
                    ticketCompletion.Owner = Owner;
                else
                    ticketCompletion.WindowStartupLocation = WindowStartupLocation.CenterScreen;

                bool? dialogResult = null;
                try
                {
                    dialogResult = ticketCompletion.ShowDialog();
                }
                catch (Exception E)
                {
                    LogException(E);
                }

                return ticketCompletion.isCanceled ? null : dialogResult;
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;
        }

        #region Close_Click

        private void Close_Click()
        {
            isCanceled = true;
            TrySetDialogResult(null);
            Close();
        }

        private void CloseButton_Click(object sender, InputEventArgs e) => Close_Click();

        #endregion

        private void TrySetDialogResult(bool? result)
        {
            try
            {
                DialogResult = result;
            }
            catch (InvalidOperationException)
            {
                // Window was not shown as dialog; ignore.
            }
        }

        private void UpdateDialogMaxHeightToScreen()
        {
            if (isUpdatingDialogBounds)
                return;

            isUpdatingDialogBounds = true;
            try
            {
                WinForms.Screen screen = null;
                IntPtr currentHandle = new WindowInteropHelper(this).Handle;

                if (currentHandle != IntPtr.Zero)
                {
                    screen = WinForms.Screen.FromHandle(currentHandle);
                }
                else if (Owner != null)
                {
                    IntPtr ownerHandle = new WindowInteropHelper(Owner).Handle;
                    if (ownerHandle != IntPtr.Zero)
                        screen = WinForms.Screen.FromHandle(ownerHandle);
                }

                screen = screen ?? WinForms.Screen.PrimaryScreen;
                var workingArea = screen?.WorkingArea ?? WinForms.Screen.PrimaryScreen.WorkingArea;
                var dpiScaleY = VisualTreeHelper.GetDpi(this).DpiScaleY;
                var safeDpiScaleY = Math.Max(0.1, dpiScaleY);
                var workingAreaTopDip = workingArea.Top / safeDpiScaleY;
                var workingAreaBottomDip = workingArea.Bottom / safeDpiScaleY;
                var workingAreaHeightDip = workingArea.Height / safeDpiScaleY;
                var availableWindowHeightDip = workingAreaHeightDip - (WindowWorkingAreaMarginDip * 2);

                MaxHeight = Math.Max(MinWindowHeightDip, availableWindowHeightDip);

                if (!double.IsNaN(Top))
                {
                    var minTop = workingAreaTopDip + WindowWorkingAreaMarginDip;
                    var maxBottom = workingAreaBottomDip - WindowWorkingAreaMarginDip;

                    if (Top < minTop)
                        Top = minTop;

                    var currentBottom = Top + ActualHeight;
                    if (currentBottom > maxBottom)
                        Top = Math.Max(minTop, maxBottom - ActualHeight);
                }

                double nonDialogReserve = DialogNonContentReserveDip;
                if (CloseCaseDialogUc != null && CloseCaseDialogUc.IsLoaded)
                {
                    var estimatedReserve = ActualHeight - CloseCaseDialogUc.ActualHeight;
                    if (estimatedReserve > 0)
                        nonDialogReserve = Math.Max(nonDialogReserve, estimatedReserve + WindowWorkingAreaMarginDip);
                }

                CloseCaseDialogUc?.SetDialogContentMaxHeight(MaxHeight - nonDialogReserve);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
            finally
            {
                isUpdatingDialogBounds = false;
            }
        }

        #region Internal Focus Events

        private void ElementGotFocus(object sender, EventArgs e)
        {
            try
            {
                FocusBorder.Visibility = Visibility.Visible;

                if (!(sender is FrameworkElement senderElement))
                    return;

                if (FocusBorder.IsVisible is false)
                    return;

                var desiredHeight = senderElement.ActualHeight;
                var desiredWidth = senderElement.ActualWidth;

                FrameworkElement placeHolderElement = new FrameworkElement() { Height = desiredHeight, Width = desiredWidth, Margin = senderElement.Margin };
                FocusDecorator.Height = desiredHeight + senderElement.Margin.Top + senderElement.Margin.Bottom;
                FocusDecorator.Width = desiredWidth + senderElement.Margin.Left + senderElement.Margin.Right;

                Point relativePoint = senderElement.TransformToAncestor(this)
                  .Transform(new Point(0, 0));

                if (senderElement.Parent is Decorator actualParentDecorator)
                    actualParentDecorator.Child = placeHolderElement;
                else if (senderElement.Parent is Panel actualParentPanel)
                {
                    if (actualParentPanel is Grid)
                    {
                        Grid.SetColumn(placeHolderElement, Grid.GetColumn(senderElement));
                        Grid.SetRow(placeHolderElement, Grid.GetRow(senderElement));
                    }

                    actualParentPanel.Children.Insert(actualParentPanel.Children.IndexOf(senderElement), placeHolderElement);
                    actualParentPanel.Children.Remove(senderElement);
                }

                Canvas.SetLeft(FocusDecorator, relativePoint.X - (senderElement.Margin.Left));
                Canvas.SetTop(FocusDecorator, relativePoint.Y - senderElement.Margin.Top);

                FocusDecorator.Child = senderElement;
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void ElementLostFocus(object sender, EventArgs e)
        {
            try
            {
                FocusBorder.Visibility = Visibility.Collapsed;
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #endregion

        private void CustomMessageBox_KeyDown(object sender, KeyEventArgs e)
        {
            if (e.Key != Key.Escape)
            {
                return;
            }

            Close_Click();
            e.Handled = true;
        }

        private async Task DoCloseActionAsync()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                WaitForClosing = true;
                SafeText.IsEnabled = false;
                AbortText.IsEnabled = false;
                IsClosingBusy = true;

                bool closedSuccessfull = await CloseCaseDialogUc.CloseCaseAsync(_dataProvider.Identities.FirstOrDefault(identity => identity.Class == enumFasdInformationClass.User).Id);

                if (closedSuccessfull)
                {
                    SuccessPage.SuccessPage successPage = new SuccessPage.SuccessPage();
                    successPage.Show();
                    await _dataProvider?.CloseCaseAsync();
                    TrySetDialogResult(true);
                    Close();
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                WaitForClosing = false;
                SafeText.IsEnabled = true;
                AbortText.IsEnabled = true;
                LogMethodEnd(CM);
            }
        }

        public void BlurInvoker_IsActiveChanged(object sender, DependencyPropertyChangedEventArgs e)
        {
            BlurInvoker.InvokeVisibilityChanged(this, new EventArgs());
        }

        public bool BlurInvoker_IsActive => IsVisible;

        public void SetButtonStateYes(bool Enabled, string MouseOverMessage)
        {
            var _h = this.Dispatcher.BeginInvoke(new Action(() =>
            {
                try
                {
                    ToolTip tip = null;

                    if (!string.IsNullOrEmpty(MouseOverMessage))
                        tip = new ToolTip { Content = MouseOverMessage };

                    SafeText.IsEnabled = Enabled;
                    GridPanel.ToolTip = tip;
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }));
        }

        public void SetButtonStateNo(bool Enabled, string MouseOverMessage)
        {
            _ = this.Dispatcher.BeginInvoke(new Action(() =>
            {
                try
                {
                    ToolTip tip = null;
                    if (!string.IsNullOrEmpty(MouseOverMessage))
                        tip = new ToolTip { Content = MouseOverMessage };

                    AbortText.IsEnabled = Enabled;
                    AbortText.ToolTip = tip;
                }
                catch (Exception E)
                {
                    LogException(E);
                }
            }));
        }

        private async void SafeText_Click(object sender, InputEventArgs e) => await DoCloseActionAsync();

        private void AbortText_Click(object sender, InputEventArgs e) => Close_Click();
    }
}

