using F4SD_AdaptableIcon.Enums;
using FasdDesktopUi.Basics.Enums;
using FasdDesktopUi.Basics.Models;
using FasdDesktopUi.Basics.UiActions;
using FasdDesktopUi.Basics.UserControls;
using FasdDesktopUi.Pages.DetailsPage.Models;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using static C4IT.Logging.cLogManager;

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

        #region WidgetGeometry DependencyProperty

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

            if (e.OldValue != null && e.NewValue != null)
            {
                var oldGeometry = e.OldValue as DetailsPageWidgetGeometryModel;
                var newGeometry = e.NewValue as DetailsPageWidgetGeometryModel;

                didGeometryChange = newGeometry.WidgetTitleCount != oldGeometry.WidgetTitleCount || didGeometryChange;
                didGeometryChange = newGeometry.WidgetDetailCount != oldGeometry.WidgetDetailCount || didGeometryChange;
            }
            else
            {
                didGeometryChange = true;
            }

            return didGeometryChange;
        }

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

            var _me = d as DetailsPageWidget;
            _me.ClearControls();
            _me.InitializeWidgetGeometry();
        }

        public static readonly DependencyProperty WidgetGeometryProperty =
            DependencyProperty.Register("WidgetGeometry", typeof(DetailsPageWidgetGeometryModel), typeof(DetailsPageWidget), new PropertyMetadata(new DetailsPageWidgetGeometryModel(), new PropertyChangedCallback(GeometryChangedCallback)));

        public DetailsPageWidgetGeometryModel WidgetGeometry
        {
            get { return (DetailsPageWidgetGeometryModel)GetValue(WidgetGeometryProperty); }
            set { SetValue(WidgetGeometryProperty, value); }
        }

        #endregion

        #region WidgetData DependencyProperty

        private static void RefreshDataCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DetailsPageWidget _me)
            {
                _me.UpdateWidgetControls();
                _me.RefreshData();
            }
        }

        public static readonly DependencyProperty WidgetDataProperty =
            DependencyProperty.Register("WidgetData", typeof(List<cWidgetValueModel>), typeof(DetailsPageWidget), new PropertyMetadata(new List<cWidgetValueModel>(), new PropertyChangedCallback(RefreshDataCallback)));

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

        #endregion

        #region WidgetHeight DependencyProperty

        public static readonly DependencyProperty WidgetHeightProperty =
            DependencyProperty.Register("WidgetHeight", typeof(double), typeof(DetailsPageWidget), new PropertyMetadata(50.0, new PropertyChangedCallback(RefreshWidgetHeightCallback)));

        public double WidgetHeight
        {
            get { return (double)GetValue(WidgetHeightProperty); }
            set { SetValue(WidgetHeightProperty, value); }
        }

        #endregion

        #endregion

        public DetailsPageWidget()
        {
            InitializeComponent();
        }

        #region SetUpControls

        #region Control Lists

        private readonly List<FrameworkElement> TitleControls = new List<FrameworkElement>();
        private readonly List<FunctionMarker> TitleFunctionMarkerControls = new List<FunctionMarker>();
        private readonly List<FrameworkElement> ValueControls = new List<FrameworkElement>();
        private readonly List<FunctionMarker> ValueFunctionMarkerControls = new List<FunctionMarker>();
        private readonly List<EditWidgetValueControl> EditControls = new List<EditWidgetValueControl>();

        #endregion

        #region Clear Controls and ControlLists

        private void ClearControls()
        {
            TitleControls.Clear();
            TitleFunctionMarkerControls.Clear();
            ValueControls.Clear();
            ValueFunctionMarkerControls.Clear();
            EditControls.Clear();
            WidgetGrid.RowDefinitions.Clear();
        }

        #endregion

        #region SetUp Functions

        private void InitializeWidgetGeometry()
        {
            try
            {
                SetUpTitleRows(WidgetGeometry.WidgetTitleCount);
                SetUpValueRows(WidgetGeometry.WidgetDetailCount);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void SetUpTitleRows(int rowsToAdd)
        {
            try
            {
                if (TitleControls.Count == 0)
                    WidgetGrid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });

                for (int i = 0; i < rowsToAdd; i++)
                {
                    WidgetGrid.RowDefinitions.Insert(TitleControls.Count, new RowDefinition { Height = GridLength.Auto });

                    StackPanel titleStackPanel = new StackPanel() { Orientation = Orientation.Horizontal };

                    TitleFunctionMarkerControls.Add(FunctionMarker.SetUpFunctionMarker(titleStackPanel, new FunctionMarker.FunctionMarkerClick(WidgetDetailsTitleFunctionMarker_Click)));

                    TextBlock title = new TextBlock() { Style = widgetTitleStyle };
                    title.Margin = new Thickness(0, 0, 0, 0);
                    titleStackPanel.Children.Add(title);
                    TitleControls.Add(title);

                    Grid.SetRow(titleStackPanel, TitleControls.Count - 1);
                    Grid.SetColumn(titleStackPanel, 0);

                    WidgetGrid.Children.Add(titleStackPanel);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void SetUpValueRows(int rowsToAdd)
        {
            try
            {
                for (int i = 0; i < rowsToAdd; i++)
                {
                    StackPanel valueDockPanel = new StackPanel() { Orientation = Orientation.Horizontal };

                    var valueFunctionMarker = FunctionMarker.SetUpFunctionMarker(valueDockPanel, new FunctionMarker.FunctionMarkerClick(WidgetDetailsValueFunctionMarker_Click));
                    ValueFunctionMarkerControls.Add(valueFunctionMarker);
                    valueFunctionMarker.Margin = new Thickness(-8, 0, -15, 0);

                    TextBlock valueTextBlock = new TextBlock() { Style = widgetValueStyle };
                    ValueControls.Add(valueTextBlock);
                    valueDockPanel.Children.Add(valueTextBlock);

                    Grid.SetRow(valueDockPanel, ValueControls.Count - 1);
                    Grid.SetColumn(valueDockPanel, 1);

                    WidgetGrid.Children.Add(valueDockPanel);

                    EditWidgetValueControl editControl = new EditWidgetValueControl() { Visibility = Visibility.Collapsed, Margin = new Thickness(10, 0, 10, 0), ParentElement = WidgetGrid };
                    var maxWidthValue = FindResource("DetailsPage.Widget.Value.MaxWidth");

                    if (maxWidthValue != null && maxWidthValue is double maxWidth)
                        editControl.MaxWidth = maxWidth - 7.5 - 7.5;

                    EditControls.Add(editControl);

                    Grid.SetRow(editControl, EditControls.Count - 1);
                    Grid.SetColumn(editControl, 1);

                    WidgetGrid.Children.Add(editControl);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #endregion

        #region Update Controls Functions

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

                UpdateWidgetTitleControls();
                UpdateWidgetValueControls();
                UpdateEditControls();
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        private void UpdateWidgetTitleControls()
        {
            try
            {
                if (TitleControls.Count < WidgetData.Count)
                {
                    SetUpTitleRows(WidgetData.Count - TitleControls.Count);
                }

                foreach (var titleControl in TitleControls)
                {
                    if (titleControl.Parent is FrameworkElement titleControlParent)
                    {
                        titleControlParent.Margin = new Thickness(0, 0, 10, 0);
                    }
                }

                if (TitleControls.First().Parent is FrameworkElement firstTitleControlParent)
                {
                    firstTitleControlParent.Margin = new Thickness(0, 15, 10, 0);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void UpdateWidgetValueControls()
        {
            try
            {
                if (ValueControls.Count < WidgetData.Count)
                {
                    SetUpValueRows(WidgetData.Count - ValueControls.Count);
                }

                if (ValueControls.First().Parent is FrameworkElement firstControlParent)
                {
                    firstControlParent.Margin = new Thickness(0, 15, 10, 0);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void UpdateEditControls()
        {
            try
            {
                for (int i = 0; i < EditControls.Count; i++)
                {
                    var currentEditControl = EditControls[i];

                    if (WidgetData.Count <= i)
                        continue;

                    if (i == 0)
                        currentEditControl.Margin = new Thickness(10, 15, 10, 0);
                    else
                        currentEditControl.Margin = new Thickness(10, 0, 10, 0);

                    var currentWidgetData = WidgetData[i];
                    currentEditControl.Visibility = Visibility.Collapsed;

                    if (currentWidgetData.EditValueInformation is null)
                        continue;

                    currentEditControl.EditableValueInformation = currentWidgetData.EditValueInformation;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #endregion

        #endregion

        #region Refresh Data

        private delegate void RefreshDelegate();

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

                RefreshWidgetTitles();
                RefreshWidgetTitleFunctionMarkers();
                RefreshWidgetValues();
                RefreshWidgetValueFunctionMarkers();
            }
            catch (Exception E)
            {
                LogException(E);
            }
            finally
            {
                LogMethodEnd(CM);
            }
        }

        private void RefreshWidgetTitles()
        {
            try
            {
                var widgetTitleEnumerator = WidgetData.GetEnumerator();

                for (int i = 0; i < TitleControls.Count; i++)
                {
                    if (widgetTitleEnumerator.MoveNext())
                    {
                        var Data = widgetTitleEnumerator.Current;
                        if (TitleControls[i] is TextBlock titleEntry)
                        {
                            titleEntry.Text = Data.Title;
                            titleEntry.Visibility = Visibility.Visible;
                        }
                    }
                    else
                    {
                        if (TitleControls[i] is TextBlock titleEntry)
                        {
                            titleEntry.Text = null;
                            titleEntry.Visibility = Visibility.Collapsed;
                        }
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void RefreshWidgetTitleFunctionMarkers()
        {
            try
            {
                var titleFunctionMarkerEnumerator = WidgetData.GetEnumerator();

                for (int i = 0; i < TitleFunctionMarkerControls.Count; i++)
                {
                    if (titleFunctionMarkerEnumerator.MoveNext())
                    {
                        var Data = titleFunctionMarkerEnumerator.Current;
                        var functionMarkerEntry = TitleFunctionMarkerControls[i];

                        if (Data.UiActionTitle != null && Data.UiActionTitle.DisplayType == enumActionDisplayType.enabled)
                        {
                            functionMarkerEntry.Tag = Data;
                            var tempToolTip = Data.UiActionTitle.Name;
                            if (!string.IsNullOrEmpty(Data.UiActionTitle.Description))
                                tempToolTip += ": \n" + Data.UiActionTitle.Description;

                            functionMarkerEntry.ToolTip = tempToolTip;
                            functionMarkerEntry.Visibility = Visibility.Visible;

                            if (Data.UiActionTitle is cShowDetailedDataAction)
                                functionMarkerEntry.SelectedIcon = enumInternIcons.misc_dot;
                            else if (Data.UiActionTitle is cUiQuickAction || Data.UiActionTitle is cSubMenuAction)
                                functionMarkerEntry.SelectedIcon = enumInternIcons.misc_functionBolt;
                        }
                        else
                        {
                            functionMarkerEntry.Tag = null;
                            functionMarkerEntry.ToolTip = null;
                            functionMarkerEntry.Visibility = Visibility.Hidden;
                        }
                    }
                    else
                    {
                        var functionMarkerEntry = TitleFunctionMarkerControls[i];
                        functionMarkerEntry.Tag = null;
                        functionMarkerEntry.ToolTip = null;
                        functionMarkerEntry.Visibility = Visibility.Collapsed;
                    }
                }

            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void RefreshWidgetValueFunctionMarkers()
        {
            try
            {
                var valueFunctionMarkerEnumerator = WidgetData.GetEnumerator();

                for (int i = 0; i < ValueFunctionMarkerControls.Count; i++)
                {
                    if (valueFunctionMarkerEnumerator.MoveNext())
                    {
                        var Data = valueFunctionMarkerEnumerator.Current;
                        var functionMarkerEntry = ValueFunctionMarkerControls[i];

                        if (Data.UiActionValue != null && Data.UiActionValue.DisplayType == enumActionDisplayType.enabled && !string.IsNullOrEmpty(Data.Value))
                        {
                            functionMarkerEntry.Visibility = Visibility.Visible;
                            functionMarkerEntry.Tag = Data;
                            var tempToolTip = Data.UiActionValue.Name;
                            if (!string.IsNullOrEmpty(Data.UiActionValue.Description))
                                tempToolTip += ": \n" + Data.UiActionValue.Description;

                            functionMarkerEntry.ToolTip = tempToolTip;

                        }
                        else
                        {
                            functionMarkerEntry.Tag = null;
                            functionMarkerEntry.ToolTip = null;
                            functionMarkerEntry.Visibility = Visibility.Hidden;
                        }
                    }
                    else
                    {
                        var functionMarkerEntry = ValueFunctionMarkerControls[i];
                        functionMarkerEntry.Tag = null;
                        functionMarkerEntry.ToolTip = null;
                        functionMarkerEntry.Visibility = Visibility.Collapsed;
                    }
                }

            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void RefreshWidgetValues()
        {
            try
            {
                var widgetDataEnumerator = WidgetData.GetEnumerator();

                for (int i = 0; i < ValueControls.Count; i++)
                {
                    if (widgetDataEnumerator.MoveNext())
                    {
                        var Data = widgetDataEnumerator.Current;
                        if (ValueControls[i] is TextBlock valueEntry)
                        {
                            valueEntry.Text = Data.IsLoading ? "..." : Data.Value;
                            valueEntry.Visibility = Visibility.Visible;
                            valueEntry.IsHitTestVisible = !string.IsNullOrWhiteSpace(Data.Value);

                            switch (Data.HighlightIn)
                            {
                                case enumHighlightColor.none:
                                    valueEntry.ClearValue(ForegroundProperty);
                                    break;
                                case enumHighlightColor.blue:
                                    valueEntry.Foreground = (SolidColorBrush)FindResource("Color.Blue");
                                    break;
                                case enumHighlightColor.green:
                                    valueEntry.Foreground = (SolidColorBrush)FindResource("Color.Green");
                                    break;
                                case enumHighlightColor.orange:
                                    valueEntry.Foreground = (SolidColorBrush)FindResource("Color.Orange");
                                    break;
                                case enumHighlightColor.red:
                                    valueEntry.Foreground = (SolidColorBrush)FindResource("Color.Red");
                                    break;
                                default:
                                    valueEntry.ClearValue(ForegroundProperty);
                                    break;
                            }
                        }
                    }
                    else
                    {
                        if (ValueControls[i] is TextBlock valueEntry)
                        {
                            valueEntry.Text = null;
                            valueEntry.Visibility = Visibility.Collapsed;
                            valueEntry.Foreground = null;
                        }
                    }
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        #endregion

        #region Refresh Widget Height

        static void RefreshWidgetHeightCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            if (d is DetailsPageWidget _me)
                _me.WidgetHeight = (double)e.NewValue;
        }

        #endregion

        #region Style Definitions

        private Style widgetTitleStyle;
        private Style widgetValueStyle;

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

        #endregion

        #region Event Methods

        #region UserControl

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

        #endregion

        #region FunctionMarker

        private void WidgetDetailsTitleFunctionMarker_Click(object sender)
        {
            if (!(sender is FrameworkElement FE))
                return;

            if (!(FE.Tag is cWidgetValueModel widgetData))
                return;

            if (widgetData.UiActionTitle == null)
                return;

            cUiActionBase.RaiseEvent(widgetData.UiActionTitle, this, this);
        }

        private void WidgetDetailsValueFunctionMarker_Click(object sender)
        {
            if (!(sender is FrameworkElement FE))
                return;

            if (!(FE.Tag is cWidgetValueModel widgetData))
                return;

            if (widgetData.UiActionValue == null)
                return;

            cUiActionBase.RaiseEvent(widgetData.UiActionValue, this, this);
        }
        #endregion

        #endregion

        public void SetEditMode(bool isActive)
        {
            try
            {
                if (WidgetData is null)
                    return;

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

                    if (currentWidgetData.EditValueInformation is null)
                        continue;

                    if (EditControls.Count > i)
                        EditControls[i].Visibility = isActive ? Visibility.Visible : Visibility.Collapsed;

                    if (ValueControls.Count > i)
                        ValueControls[i].Visibility = isActive ? Visibility.Collapsed : Visibility.Visible;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }


    }
}