using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Globalization;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;

using FasdDesktopUi.Pages.DetailsPage.Models;

using C4IT.Logging;
using static C4IT.Logging.cLogManager;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics;

namespace FasdDesktopUi.Pages.DetailsPage.UserControls
{
    public partial class DetailsPageWidgetCollection : UserControl
    {
        #region Properties

        private bool isNewCase = true;

        #region WidgetGeometryList DependencyProperty

        private static bool DidGeometryDataChanged(DependencyPropertyChangedEventArgs e)
        {
            bool didGeometryChange = false;

            try
            {
                if (e.NewValue != null && e.OldValue != null)
                {
                    var oldValueEnumerator = (e.OldValue as List<DetailsPageWidgetGeometryModel>).GetEnumerator();
                    var newValues = e.NewValue as List<DetailsPageWidgetGeometryModel>;

                    foreach (var value in newValues)
                    {
                        if (oldValueEnumerator.MoveNext())
                        {
                            didGeometryChange = value.WidgetTitleCount != oldValueEnumerator.Current.WidgetTitleCount || didGeometryChange;
                            didGeometryChange = value.WidgetDetailCount != oldValueEnumerator.Current.WidgetDetailCount || didGeometryChange;
                        }
                        else
                        {
                            didGeometryChange = true;
                        }
                    }
                }
                else
                {
                    didGeometryChange = true;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return didGeometryChange;
        }

        private static void GeometryChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (DidGeometryDataChanged(e) is false)
                return;

            var _me = d as DetailsPageWidgetCollection;
            _me.InitializeCollectionGeometry();
        }

        public static readonly DependencyProperty WidgetGeometryListProperty =
            DependencyProperty.Register("WidgetGeometryList", typeof(List<DetailsPageWidgetGeometryModel>), typeof(DetailsPageWidgetCollection), new PropertyMetadata(new List<DetailsPageWidgetGeometryModel>(), new PropertyChangedCallback(GeometryChangedCallback)));

        public List<DetailsPageWidgetGeometryModel> WidgetGeometryList
        {
            get { return (List<DetailsPageWidgetGeometryModel>)GetValue(WidgetGeometryListProperty); }
            set { SetValue(WidgetGeometryListProperty, value); }
        }

        #endregion

        #region WidgetDataList DependencyProperty

        static void RefreshDataCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DetailsPageWidgetCollection _me)
            {
                _me.UpdateWidgetBar();
                _me.RefreshData();
            }
        }

        public static readonly DependencyProperty WidgetDataListProperty =
            DependencyProperty.Register("WidgetDataList", typeof(List<List<cWidgetValueModel>>), typeof(DetailsPageWidgetCollection), new PropertyMetadata(new List<List<cWidgetValueModel>>(), new PropertyChangedCallback(RefreshDataCallback)));

        public List<List<cWidgetValueModel>> WidgetDataList
        {
            get { return (List<List<cWidgetValueModel>>)GetValue(WidgetDataListProperty); }
            set { SetValue(WidgetDataListProperty, value); }
        }

        #endregion

        #endregion

        public DetailsPageWidgetCollection()
        {
            InitializeComponent();
        }

        protected override void OnInitialized(EventArgs e)
        {
            base.OnInitialized(e);
            cSupportCaseDataProvider.CaseChanged += (sender, args) => isNewCase = true;
        }


        #region SetUp Controls

        #region Control Lists

        private readonly List<DetailsPageWidget> WidgetControls = new List<DetailsPageWidget>();

        #endregion

        #region SetUpFunctions

        private void InitializeCollectionGeometry()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (DesignerProperties.GetIsInDesignMode(this) || WidgetGeometryList == null)
                    return;

                WidgetControls.Clear();
                WidgetSectionStackPanel.Children.RemoveRange(0, WidgetSectionStackPanel.Children.Count - 1);

                for (int i = 0; i < WidgetGeometryList.Count; i++)
                {
                    Border widgetBorder = new Border() { Background = Brushes.Transparent, AllowDrop = true, Padding = new Thickness(0, 0, 25, 0), Tag = "WidgetDataBorder" };

                    DetailsPageWidget widgetToCreate = new DetailsPageWidget() { WidgetGeometry = WidgetGeometryList[i] };

                    widgetBorder.Child = widgetToCreate;
                    WidgetSectionStackPanel.Children.Add(widgetBorder);
                    WidgetControls.Add(widgetToCreate);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        #endregion

        #endregion

        #region Update Controls Function

        private void UpdateWidgetBar()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (WidgetDataList == null)
                    return;

                if (WidgetDataList.Count > WidgetControls.Count)
                {
                    int missingWidgetData = WidgetDataList.Count - WidgetControls.Count;
                    LogEntry($"WidgetCollection - {missingWidgetData} widgets were missing and had to be added."); //todo: remove

                    for (int i = 0; i < missingWidgetData; i++)
                    {
                        Border widgetBorder = new Border() { Background = Brushes.Transparent, AllowDrop = true, Padding = new Thickness(0, 0, 25, 0), Tag = "WidgetDataBorder" };

                        DetailsPageWidget widgetToCreate = new DetailsPageWidget();

                        widgetBorder.Child = widgetToCreate;
                        WidgetSectionStackPanel.Children.Add(widgetBorder);
                        WidgetControls.Add(widgetToCreate);
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        #endregion

        #region Refresh Data

        private void RefreshData()
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (WidgetDataList == null)
                    return;

                var WidgetDataEnumerator = WidgetDataList.GetEnumerator();

                foreach (var widgetControl in WidgetControls)
                {
                    if (WidgetDataEnumerator.MoveNext())
                    {
                        var widgetData = WidgetDataEnumerator.Current;

                        widgetControl.WidgetHeight = GetWidgetHeight();
                        widgetControl.Visibility = widgetData?.Count > 0 ? Visibility.Visible : Visibility.Collapsed;
                        widgetControl.WidgetData = widgetData;
                    }
                    else
                    {
                        widgetControl.WidgetData = null;
                        widgetControl.Visibility = Visibility.Collapsed;
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        #endregion

        #region Update Data

        public void UpdateWidgetData(List<List<cWidgetValueModel>> widgetData)
        {
            try
            {
                if (WidgetDataList is null || WidgetDataList.Count == 0)
                    return;

                var widgetDataEnumerator = WidgetDataList.GetEnumerator();

                for (int i = 0; i < widgetData.Count; i++)
                {
                    var widgetCategory = widgetData[i];

                    widgetDataEnumerator.MoveNext();

                    var currentHistoryData = widgetDataEnumerator.Current;

                    var didWidgetCategoryChange = isNewCase || DidWidgetCategoryChange(currentHistoryData, widgetCategory);
                    LogEntry($"WidgetCollection - WidgetData for Widget {i} did {(didWidgetCategoryChange ? "" : "NOT")} change."); //todo: remove

                    if (didWidgetCategoryChange && WidgetControls[i] != null)
                        WidgetControls[i].WidgetData = widgetCategory;
                }

                WidgetDataList = widgetData;
                isNewCase = false;
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private bool DidWidgetCategoryChange(List<cWidgetValueModel> oldValue, List<cWidgetValueModel> newValue)
        {
            var CM = MethodBase.GetCurrentMethod();
            LogMethodBegin(CM);
            try
            {
                if (oldValue is null || newValue is null)
                    return true;

                if (oldValue.Count != newValue.Count)
                    return true;

                var newValueRowEnumeator = newValue.GetEnumerator();

                foreach (var oldValueRow in oldValue)
                {
                    if (!newValueRowEnumeator.MoveNext())
                        continue;

                    var currentNewValueRow = newValueRowEnumeator.Current;

                    if (oldValueRow?.Value != currentNewValueRow?.Value)
                        return true;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }

            return false;
        }

        #endregion

        #region Style Definitions

        private Style widgetTitleStyle;

        private void SetStyles()
        {
            widgetTitleStyle = (Style)FindResource("DetailsPage.Widget.Title");
        }

        private static Size MeasureStringSize(string stringToMeasure, Control controlOfText)
        {
            var formattedText = new FormattedText(
                stringToMeasure,
                CultureInfo.CurrentCulture,
                FlowDirection.LeftToRight,
                new Typeface(controlOfText.FontFamily, controlOfText.FontStyle, controlOfText.FontWeight, controlOfText.FontStretch),
                controlOfText.FontSize,
                Brushes.Black,
                new NumberSubstitution(),
                1);

            return new Size(formattedText.Width, formattedText.Height);
        }

        private double GetWidgetHeight()
        {
            double widgetHeight = 150;

            foreach (var widgetData in WidgetDataList)
            {
                double tempWidgetHeight = 0;
                foreach (var widget in widgetData)
                {
                    if (widget.Title == null)
                        continue;

                    tempWidgetHeight += MeasureStringSize(widget.Title, new Control { Style = widgetTitleStyle }).Height + 14; // 14 = FunctionMarkerBorderHeight - FontSize
                }

                tempWidgetHeight += 4;

                if (tempWidgetHeight > widgetHeight)
                    widgetHeight = tempWidgetHeight;
            }

            return widgetHeight;
        }

        #endregion

        #region Event Methods

        private void DetailsPageWidgetCollection_Initialized(object sender, EventArgs e)
        {
            SetStyles();
        }

        private void ScrollViewer_PreviewMouseWheel(object sender, MouseWheelEventArgs e)
        {
            if (!(sender is ScrollViewer scrollViewer))
                return;

            var destination = scrollViewer.HorizontalOffset - e.Delta;
            scrollViewer.ScrollToHorizontalOffset(destination);
        }

        private void ScrollViewer_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            e.Handled = true;
        }

        #region Click Events

        private void WidgetSectionStackPanel_Click(object originalSource)
        {
            try
            {
                if (!(originalSource is TextBlock clickedTextBlock))
                    return;

                System.Windows.Forms.Clipboard.SetText(clickedTextBlock.Text);
            }
            catch { }
        }

        private void WidgetSectionStackPanel_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            WidgetSectionStackPanel_Click(e.OriginalSource);
        }

        private void WidgetSectionStackPanel_TouchDown(object sender, TouchEventArgs e)
        {
            WidgetSectionStackPanel_Click(e.OriginalSource);
        }

        #endregion

        #endregion

        public void SetEditMode(bool isActive)
        {
            try
            {
                foreach (var child in WidgetSectionStackPanel.Children)
                {
                    if (!(child is Border widgetBorder && widgetBorder.Child is DetailsPageWidget widget))
                        continue;

                    widget.SetEditMode(isActive);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }
    }
}