using C4IT.FASD.Base;
using C4IT.FASD.Cockpit.Communication;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using static C4IT.Logging.cLogManager;

namespace FasdDesktopUi.Basics.UserControls
{
    public partial class ForwardTicketDialog : UserControl
    {
        private readonly cSupportCaseDataProvider _dataProvider;
        private static readonly Brush ValidationBrush = CreateValidationBrush();
        private static Brush CreateValidationBrush()
        {
            var brush = new SolidColorBrush(Color.FromRgb(0xF5, 0x7C, 0x73));
            if (brush.CanFreeze)
                brush.Freeze();
            return brush;
        }

        private Brush defaultRoleBorderBrush;
        private Brush defaultPersonBorderBrush;
        private Thickness? defaultRoleBorderThickness;
        private Thickness? defaultPersonBorderThickness;

        string lastPersonSearch = string.Empty;
        string lastRoleSearch = string.Empty;

        public event EventHandler SelectedRoleChanged;
        public event EventHandler SelectedPersonChanged;
        public event EventHandler CommentChanged;

        public string Comment
        {
            get { return (string)GetValue(CommentProperty); }
            set { SetValue(CommentProperty, value); }
        }

        // Using a DependencyProperty as the backing store for Comment.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty CommentProperty =
            DependencyProperty.Register("Comment", typeof(string), typeof(ForwardTicketDialog), new PropertyMetadata(string.Empty, OnCommentChanged));

        private static void OnCommentChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ForwardTicketDialog)d;
            control.CommentChanged?.Invoke(control, EventArgs.Empty);
        }

        public KeyValuePair<string, object> SelectedRole
        {
            get { return (KeyValuePair<string, object>)GetValue(SelectedRoleProperty); }
            set { SetValue(SelectedRoleProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelectedRole. This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedRoleProperty =
            DependencyProperty.Register("SelectedRole", typeof(KeyValuePair<string, object>), typeof(ForwardTicketDialog), new PropertyMetadata(default(KeyValuePair<string, object>), OnSelectedRoleChanged));

        private static void OnSelectedRoleChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ForwardTicketDialog)d;
            control.SelectedRoleChanged?.Invoke(control, EventArgs.Empty);
        }

        public KeyValuePair<string, object> SelectedPerson
        {
            get { return (KeyValuePair<string, object>)GetValue(SelectedPersonProperty); }
            set { SetValue(SelectedPersonProperty, value); }
        }

        // Using a DependencyProperty as the backing store for SelectedPerson. This enables animation, styling, binding, etc...
        public static readonly DependencyProperty SelectedPersonProperty =
            DependencyProperty.Register("SelectedPerson", typeof(KeyValuePair<string, object>), typeof(ForwardTicketDialog), new PropertyMetadata(default(KeyValuePair<string, object>), OnSelectedPersonChanged));

        private static void OnSelectedPersonChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var control = (ForwardTicketDialog)d;
            control.SelectedPersonChanged?.Invoke(control, EventArgs.Empty);
        }


        public ForwardTicketDialog(cSupportCaseDataProvider dataProvider)
        {
            InitializeComponent();
            _dataProvider = dataProvider;
            defaultRoleBorderBrush = RoleValidationBorder?.BorderBrush?.CloneCurrentValue();
            defaultPersonBorderBrush = PersonValidationBorder?.BorderBrush?.CloneCurrentValue();
            defaultRoleBorderThickness = RoleValidationBorder?.BorderThickness;
            defaultPersonBorderThickness = PersonValidationBorder?.BorderThickness;
            UpdateResponsibleSelectionValidationState(true);
        }

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

            PersonSelectionControl.SearchDataChanged = HandlePersonSearchDataChanged;
            PersonSelectionControl.ParentElement = MainStack;
            PersonSelectionControl.ParentIndex = MainStack.Children.IndexOf(PersonSelectionControl);

            RoleSelectionControl.SearchDataChanged = HandleRoleSearchDataChanged;
            RoleSelectionControl.ParentElement = MainStack;
            RoleSelectionControl.ParentIndex = MainStack.Children.IndexOf(RoleSelectionControl);
        }

        private async void HandlePersonSearchDataChanged(object sender, cF4sdHealthSelectionDataRequest e) => await UpdatePersonSelectionControlAsync(e);

        private async Task UpdatePersonSelectionControlAsync(cF4sdHealthSelectionDataRequest requestData)
        {
            try
            {
                requestData.Identities = _dataProvider?.Identities;
                requestData.Table = "M42Wpm-Ticket-Persons";

                if (string.IsNullOrEmpty(lastPersonSearch) || !lastPersonSearch.Equals(requestData.Search, StringComparison.CurrentCultureIgnoreCase))
                {
                    var peopleCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData);
                    PersonSelectionControl.TotalItemCount = peopleCount;
                }
                lastPersonSearch = requestData.Search;

                var peopleData = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData);
                PersonSelectionControl.ItemData = GetPeopleSelectionData(peopleData);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private ObservableCollection<KeyValuePair<string, object>> GetPeopleSelectionData(cF4SDHealthCardRawData.cHealthCardTable dataTable)
        {
            try
            {
                if (dataTable is null || dataTable.Name != "M42Wpm-Ticket-Persons")
                    return null;

                if (!dataTable.Columns.TryGetValue("id", out var idColumn))
                    return null;

                dataTable.Columns.TryGetValue("LastName", out var lastNameColumn);
                dataTable.Columns.TryGetValue("FirstName", out var firstNameColumn);
                dataTable.Columns.TryGetValue("Position", out var positionColumn);

                var zippedNames = lastNameColumn.Values.Zip(firstNameColumn.Values, (lastName, firstName) => $"{lastName}, {firstName}");

                var zippedKeyValuePairs = idColumn.Values.Zip(zippedNames, (id, display) => new KeyValuePair<string, object>(display, id));

                return new ObservableCollection<KeyValuePair<string, object>>(zippedKeyValuePairs);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;
        }

        private async void HandleRoleSearchDataChanged(object sender, cF4sdHealthSelectionDataRequest e) => await UpdateRoleSelectionControlAsync(e);

        private async Task UpdateRoleSelectionControlAsync(cF4sdHealthSelectionDataRequest requestData)
        {
            try
            {
                requestData.Identities = _dataProvider?.Identities;
                requestData.Table = "M42Wpm-Ticket-Roles";


                if (string.IsNullOrEmpty(lastRoleSearch) || !lastRoleSearch.Equals(requestData.Search, StringComparison.CurrentCultureIgnoreCase))
                {
                    var roleCount = await cFasdCockpitCommunicationBase.Instance.GetPagedDataCount(requestData);
                    RoleSelectionControl.TotalItemCount = roleCount;
                }
                lastRoleSearch = requestData.Search;

                var roleData = await cFasdCockpitCommunicationBase.Instance.GetPagedData(requestData);
                RoleSelectionControl.ItemData = GetRoleSelectionData(roleData);
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }

        private ObservableCollection<KeyValuePair<string, object>> GetRoleSelectionData(cF4SDHealthCardRawData.cHealthCardTable dataTable)
        {
            try
            {
                if (dataTable is null || dataTable.Name != "M42Wpm-Ticket-Roles")
                    return null;

                if (!dataTable.Columns.TryGetValue("id", out var idColumn))
                    return null;

                dataTable.Columns.TryGetValue("Name", out var nameColumn);

                var zippedKeyValuePairs = idColumn.Values.Zip(nameColumn.Values, (id, display) => new KeyValuePair<string, object>(display.ToString(), id));

                return new ObservableCollection<KeyValuePair<string, object>>(zippedKeyValuePairs);
            }
            catch (Exception E)
            {
                LogException(E);
            }

            return null;
        }

        public void UpdateResponsibleSelectionValidationState(bool hasError)
        {
            try
            {
                if (RoleValidationBorder != null)
                {
                    if (defaultRoleBorderBrush == null)
                        defaultRoleBorderBrush = RoleValidationBorder.BorderBrush?.CloneCurrentValue();
                    if (defaultRoleBorderThickness == null)
                        defaultRoleBorderThickness = RoleValidationBorder.BorderThickness;
                    RoleValidationBorder.BorderBrush = hasError ? ValidationBrush : defaultRoleBorderBrush;
                    RoleValidationBorder.BorderThickness = hasError ? new Thickness(1) : defaultRoleBorderThickness ?? new Thickness(0);
                }

                if (PersonValidationBorder != null)
                {
                    if (defaultPersonBorderBrush == null)
                        defaultPersonBorderBrush = PersonValidationBorder.BorderBrush?.CloneCurrentValue();
                    PersonValidationBorder.BorderBrush = hasError ? ValidationBrush : defaultPersonBorderBrush;
                    if (defaultPersonBorderThickness == null)
                        defaultPersonBorderThickness = PersonValidationBorder.BorderThickness;
                    PersonValidationBorder.BorderThickness = hasError ? new Thickness(1) : defaultPersonBorderThickness ?? new Thickness(0);
                }
            }
            catch (Exception E)
            {
                LogException(E);
            }
        }
    }
}
