using C4IT.FASD.Base;

using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using static C4IT.Logging.cLogManager;
using static FasdDesktopUi.Basics.UserControls.QuickActionStatusMonitor;

namespace FasdDesktopUi.Basics.UserControls
{
    public partial class QuickActionStatusMonitorResultElement : UserControl
    {
        private const string secretTag = "Secret";
        private const string veiledTextTag = "ClearText";

        public QuickActionStatusMonitorResultElement()
        {
            InitializeComponent();
        }

        public void SetQuickActionOutputData(cF4sdQuickActionRevision.cOutput output, cSupportCaseDataProvider dataProvider, cFasdQuickAction quickActionDefinition)
        {
            try
            {
                ResetQuickActionResultGrid();

                if (output is null)
                    return;

                if (output.ResultCode == enumQuickActionSuccess.successfull)
                    PartyPopperGif.Visibility = Visibility.Visible;

                if (cQuickActionOutput.HasError(output))
                    SetErrorOutput(output);
                else
                    QuickActionErrorContainer.Visibility = Visibility.Collapsed;

                var quickActionOutput = cQuickActionOutput.GetQuickActionOutput(output, dataProvider);

                switch (quickActionOutput)
                {
                    case cQuickActionOutputSingle singleOutput:
                        SetSingleOutput(singleOutput, quickActionDefinition);
                        break;
                    case cQuickActionOutputList listOutput:
                        SetListOutput(listOutput, quickActionDefinition);
                        break;
                    case cQuickActionOutputObject objectOutput:
                        SetObjectOutput(objectOutput, quickActionDefinition);
                        break;
                    default:
                        break;
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private void ResetQuickActionResultGrid()
        {
            QuickActionResultGrid.Children.Clear();
            QuickActionResultGrid.RowDefinitions.Clear();
            QuickActionResultGrid.ColumnDefinitions.Clear();
        }

        private void SetErrorOutput(cF4sdQuickActionRevision.cOutput output)
        {
            try
            {
                if (output is null)
                    return;

                if (output.ResultCode != null
                    && output.ResultCode.Value != enumQuickActionSuccess.unknown
                    && output.ResultCode.Value != enumQuickActionSuccess.error)
                {
                    ResultCodeLabel.Visibility = Visibility.Collapsed;
                    ResultCodeText.Visibility = Visibility.Collapsed;
                }
                else
                {
                    ResultCodeLabel.Visibility = Visibility.Visible;
                    ResultCodeText.Visibility = Visibility.Visible;
                    ResultCodeText.Text = output?.ResultCode?.ToString();
                }

                if (output?.ErrorCode != null && output?.ErrorCode != 0)
                {
                    ErrorCodeLabel.Visibility = Visibility.Visible;
                    ErrorCodeText.Visibility = Visibility.Visible;
                    var strErr = output?.ErrorCode?.ToString() ?? "";

                    var unsigned = (uint)(output.ErrorCode);
                    var strHex = unsigned.ToString("X");
                    strErr += " (0x" + strHex + ")";

                    ErrorCodeText.Text = strErr;
                }
                else
                {
                    ErrorCodeLabel.Visibility = Visibility.Collapsed;
                    ErrorCodeText.Visibility = Visibility.Collapsed;
                }

                if (!string.IsNullOrEmpty(output?.ErrorDescription))
                {
                    ErrorDescrLabel.Visibility = Visibility.Visible;
                    ErrorDescrText.Visibility = Visibility.Visible;
                    ErrorDescrText.Text = output?.ErrorDescription;
                }
                else
                {
                    ErrorDescrLabel.Visibility = Visibility.Collapsed;
                    ErrorDescrText.Visibility = Visibility.Collapsed;
                }

                QuickActionErrorContainer.Visibility = Visibility.Visible;
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void SetSingleOutput(cQuickActionOutputSingle output, cFasdQuickAction quickActionDefinition)
        {
            try
            {
                if (output.Value is null)
                    return;

                string displayValue = output.GetDisplayValue(quickActionDefinition.ColumnOutputFormattings);
                var resultTextBlock = new TextBlock() { Text = !string.IsNullOrWhiteSpace(displayValue) ? displayValue : null };
                resultTextBlock.SetResourceReference(Control.CursorProperty, "Cursor.Copy");
                resultTextBlock.MouseLeftButtonUp += ValueTextBlock_Click;
                resultTextBlock.TouchDown += ValueTextBlock_Click;

                cColumnOutputFormatting formatting = null;
                if (output.Key != null)
                    quickActionDefinition.ColumnOutputFormattings.TryGetValue(output.Key, out formatting);
                formatting = formatting ?? quickActionDefinition.ColumnOutputFormattings?.Values?.FirstOrDefault();

                if (formatting != null)
                {
                    string displayValueSecret = output.GetDisplayValue(quickActionDefinition.ColumnOutputFormattings, true);
                    var resultTextBlockSecret = new TextBlock() { Text = !string.IsNullOrWhiteSpace(displayValueSecret) ? displayValueSecret : null, Visibility = Visibility.Collapsed, Tag = secretTag };
                    resultTextBlockSecret.SetResourceReference(Control.CursorProperty, "Cursor.Copy");
                    resultTextBlockSecret.MouseLeftButtonUp += ValueTextBlock_Click;
                    resultTextBlockSecret.TouchDown += ValueTextBlock_Click;
                    ReplaceClickSenderOf(resultTextBlock, resultTextBlockSecret);

                    resultTextBlock.Tag = veiledTextTag;
                    QuickActionResultGrid.Children.Add(resultTextBlockSecret);
                }

                QuickActionResultGrid.Children.Add(resultTextBlock);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void SetListOutput(cQuickActionOutputList listOutput, cFasdQuickAction quickActionDefinition)
        {
            try
            {
                if (listOutput.Values is null || listOutput.Values.Count <= 0)
                    return;

                var columnFormattings = quickActionDefinition.ColumnOutputFormattings;
                List<KeyValuePair<string, object>> headingValues = listOutput.Values[0];

                QuickActionResultGrid.RowDefinitions.Add(new RowDefinition());

                for (int i = 0; i < headingValues.Count; i++)
                {
                    QuickActionResultGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });

                    string columnKey = headingValues[i].Key;

                    if (cUtility.ShouldHideQuickActionOutput(columnKey, quickActionDefinition))
                        continue;

                    string displayValue = columnKey;
                    if (quickActionDefinition.ColumnOutputFormattings?.TryGetValue(columnKey, out var columnFormatting) ?? false)
                        displayValue = columnFormatting.Names.GetValue();

                    TextBlock headingTextBlock = new TextBlock() { Text = displayValue };
                    Border headingBorder = new Border() { Child = headingTextBlock };
                    Grid.SetRow(headingBorder, 0);
                    Grid.SetColumn(headingBorder, i);
                    QuickActionResultGrid.Children.Add(headingBorder);
                }

                for (int row = 0; row < listOutput.Values.Count; row++)
                {
                    QuickActionResultGrid.RowDefinitions.Add(new RowDefinition());

                    for (int column = 0; column < listOutput.Values[row].Count; column++)
                    {
                        string columnKey = listOutput.Values[0][column].Key;

                        if (cUtility.ShouldHideQuickActionOutput(columnKey, quickActionDefinition))
                            continue;

                        string displayValue = listOutput.GetDisplayValue(row, column, columnFormattings);

                        if (string.IsNullOrEmpty(displayValue))
                            continue;

                        TextBlock valueTextBlock = new TextBlock { FontWeight = FontWeights.Normal, Text = displayValue };
                        valueTextBlock.SetResourceReference(Control.CursorProperty, "Cursor.Copy");
                        valueTextBlock.MouseLeftButtonUp += ValueTextBlock_Click;
                        valueTextBlock.TouchDown += ValueTextBlock_Click;
                        Border valueBorder = new Border() { Child = valueTextBlock };
                        Grid.SetRow(valueBorder, row + 1);
                        Grid.SetColumn(valueBorder, column);

                        bool hasSecretValue = columnFormattings?[columnKey]?.IsSecret ?? false;
                        if (hasSecretValue)
                        {
                            string displayValueSecret = listOutput.GetDisplayValue(row, column, columnFormattings, true);
                            TextBlock valueTextBlockSecret = new TextBlock { FontWeight = FontWeights.Normal, Text = displayValueSecret };
                            valueTextBlockSecret.SetResourceReference(Control.CursorProperty, "Cursor.Copy");
                            valueTextBlockSecret.MouseLeftButtonUp += ValueTextBlock_Click;
                            valueTextBlockSecret.TouchDown += ValueTextBlock_Click;
                            ReplaceClickSenderOf(valueTextBlock, valueTextBlockSecret);

                            Border valueBorderSecret = new Border() { Child = valueTextBlockSecret, Visibility = Visibility.Collapsed, Tag = secretTag };

                            valueBorder.Tag = veiledTextTag;

                            Grid.SetRow(valueBorderSecret, row + 1);
                            Grid.SetColumn(valueBorderSecret, column);
                            QuickActionResultGrid.Children.Add(valueBorderSecret);
                        }

                        QuickActionResultGrid.Children.Add(valueBorder);
                    }
                }
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void SetObjectOutput(cQuickActionOutputObject objectOutput, cFasdQuickAction quickActionDefinition)
        {
            try
            {
                if (objectOutput.Values?.Count <= 0)
                    return;

                QuickActionResultGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });

                for (int i = 0; i < objectOutput.Values.Count; i++)
                {
                    string columnKey = objectOutput.Values[i].Key;

                    // Has to be done, no matter if value should be hidden. Else the following Grid.SetRow's affect the wrong row.
                    QuickActionResultGrid.RowDefinitions.Add(new RowDefinition() { Height = GridLength.Auto });

                    if (cUtility.ShouldHideQuickActionOutput(columnKey, quickActionDefinition))
                        continue;

                    string displayValue = columnKey;
                    if (quickActionDefinition.ColumnOutputFormattings?.TryGetValue(columnKey, out var columnFormatting) ?? false)
                        displayValue = columnFormatting.Names.GetValue();

                    TextBlock headingTextBlock = new TextBlock() { Text = displayValue };

                    Border headingBorder = new Border() { Child = headingTextBlock };
                    Grid.SetColumn(headingBorder, 0);
                    Grid.SetRow(headingBorder, i);
                    QuickActionResultGrid.Children.Add(headingBorder);
                }

                QuickActionResultGrid.ColumnDefinitions.Add(new ColumnDefinition() { Width = new GridLength(0, GridUnitType.Auto) });

                for (int i = 0; i < objectOutput.Values.Count; i++)
                {
                    string columnKey = objectOutput.Values[i].Key;
                    if (cUtility.ShouldHideQuickActionOutput(columnKey, quickActionDefinition))
                        continue;

                    string displayValue = objectOutput.GetDisplayValue(i, quickActionDefinition.ColumnOutputFormattings);
                    if (string.IsNullOrWhiteSpace(displayValue))
                        continue;

                    TextBlock valueTextBlock = new TextBlock() { FontWeight = FontWeights.Normal, Text = displayValue };
                    valueTextBlock.SetResourceReference(Control.CursorProperty, "Cursor.Copy");
                    valueTextBlock.MouseLeftButtonUp += ValueTextBlock_Click;
                    valueTextBlock.TouchDown += ValueTextBlock_Click;

                    Border valueBorder = new Border() { Child = valueTextBlock };
                    Grid.SetRow(valueBorder, i);
                    Grid.SetColumn(valueBorder, 1);
                    QuickActionResultGrid.Children.Add(valueBorder);

                    if (quickActionDefinition.ColumnOutputFormattings is null || string.IsNullOrWhiteSpace(columnKey))
                        continue;

                    if (quickActionDefinition.ColumnOutputFormattings.TryGetValue(columnKey, out var formatting) && (formatting?.IsSecret ?? false))
                    {
                        string displayValueSecret = objectOutput.GetDisplayValue(i, quickActionDefinition.ColumnOutputFormattings, true);

                        TextBlock valueTextBlockSecret = new TextBlock() { FontWeight = FontWeights.Normal, Text = displayValueSecret };
                        valueTextBlockSecret.SetResourceReference(Control.CursorProperty, "Cursor.Copy");
                        valueTextBlockSecret.MouseLeftButtonUp += ValueTextBlock_Click;
                        valueTextBlockSecret.TouchDown += ValueTextBlock_Click;
                        ReplaceClickSenderOf(valueTextBlock, valueTextBlockSecret);

                        Border valueBorderSecret = new Border() { Child = valueTextBlockSecret, Visibility = Visibility.Collapsed, Tag = secretTag };
                        Grid.SetRow(valueBorderSecret, i);
                        Grid.SetColumn(valueBorderSecret, 1);
                        QuickActionResultGrid.Children.Add(valueBorderSecret);

                        valueBorder.Tag = veiledTextTag;
                    }
                }
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        private void ValueTextBlock_Click(object sender, InputEventArgs e)
        {
            try
            {
                if (!(sender is TextBlock textBlock))
                    return;

                System.Windows.Forms.Clipboard.SetText(textBlock.Text);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }

        }

        private void ReplaceClickSenderOf(UIElement from, UIElement to)
        {
            try
            {
                from.MouseLeftButtonUp -= ValueTextBlock_Click;
                from.TouchDown -= ValueTextBlock_Click;

                from.MouseLeftButtonUp += (s, e) => ValueTextBlock_Click(to, e);
                from.TouchDown += (s, e) => ValueTextBlock_Click(to, e);
            }
            catch (Exception ex)
            {
                LogException(ex);
            }
        }

        internal void ToggleSecretVisibility(bool secretsAreShown)
        {
            try
            {
                var taggedResultElements = QuickActionResultGrid.Children.OfType<FrameworkElement>().Where(element => element.Tag != null);

                foreach (var resultElement in taggedResultElements)
                {
                    if (resultElement.Tag.Equals(secretTag))
                        resultElement.Visibility = secretsAreShown ? Visibility.Visible : Visibility.Collapsed;
                    if (resultElement.Tag.Equals(veiledTextTag))
                        resultElement.Visibility = secretsAreShown ? Visibility.Collapsed : Visibility.Visible;
                }
            }
            catch (Exception ex)
            {
                LogException(ex);
            }

        }
    }
}
