using InABox.Core;
using InABox.WPF;
using NPOI.HPSF;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Effects;
using System.Windows.Media.Imaging;

namespace InABox.DynamicGrid
{
    public class DFMultiImageControl : DynamicFormFieldControl<DFLayoutMultiImage, DFLayoutMultiImageProperties, List<Guid>, DFLayoutEmbeddedMediaValues>
    {
        private DFLayoutEmbeddedMediaValues _value = null!;
        
        private Grid Grid = null!; // Late-initialised
        private StackPanel Images = null!; // Late-initialised
        private bool Enabled = true;

        static DFMultiImageControl()
        {
            IsEnabledProperty.OverrideMetadata(
                typeof(DFMultiImageControl),
                new UIPropertyMetadata(
                    true,
                    ControlIsEnabledChanged));
        }

        private static void ControlIsEnabledChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e)
        {
            var control = (DFMultiImageControl)obj;
            control.IsEnabled = true;
            control.Enabled = (bool)e.NewValue;
        }

        protected override FrameworkElement Create()
        {
            _value = new DFLayoutEmbeddedMediaValues();
            
            Grid = new Grid();
            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });
            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
            Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = GridLength.Auto });

            Grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
            Grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });

            var imagesScroll = new ScrollViewer
            {
                HorizontalScrollBarVisibility = ScrollBarVisibility.Auto,
                VerticalScrollBarVisibility = ScrollBarVisibility.Disabled,
                Background = new SolidColorBrush(Colors.Gray)
            };

            Images = new StackPanel { Orientation = Orientation.Horizontal, Height = 200 };

            imagesScroll.Content = Images;

            var clearButton = new Button
            {
                Content = "Clear",
                Margin = new Thickness(0, 5, 0, 0),
                Width = 60,
                Height = 35
            };
            clearButton.Click += MultiImageClear_Click;

            var addButton = new Button
            {
                Content = "Add",
                Margin = new Thickness(0, 5, 0, 0),
                Width = 60,
                Height = 35
            };
            addButton.Click += MultiImageAdd_Click;

            imagesScroll.SetGridPosition(0, 0, 1, 3);
            clearButton.SetGridPosition(1, 0, 1, 1);
            addButton.SetGridPosition(1, 2, 1, 1);
            Grid.Children.Add(imagesScroll);
            Grid.Children.Add(clearButton);
            Grid.Children.Add(addButton);

            return Grid;
        }
        
        private void AddMultiImage(DFLayoutEmbeddedMediaValue value)// byte[]? data)
        {
            _value.Add(value);
            value.Thumbnail ??= value.Data != null
                ? ImageUtils.BitmapImageFromBytes(value.Data)?.Resize(200, 200).ToArray<BmpBitmapEncoder>()
                : new System.Drawing.Bitmap(256, 256).WatermarkImage("No Image", System.Drawing.Color.Gray).AsBitmapImage().ToArray<BmpBitmapEncoder>();

            var border = new Border
            {
                Effect = new DropShadowEffect
                {
                    ShadowDepth = 0,
                    BlurRadius = 10
                }
            };

            var image = new Image
            {
                Margin = new Thickness(5)
            };
            var source = value.Data != null
                ? ImageUtils.BitmapImageFromBytes(value.Data)
                : value.Thumbnail != null
                    ? ImageUtils.BitmapImageFromBytes(value.Thumbnail)
                    : null;
            if (source != null)
            {
                image.Source = source;

                var menu = new ContextMenu();
                menu.AddItem("View Image", null, value, MultiImageView_Click);
                if (Enabled)
                {
                    menu.AddItem("Remove Image", null, ((FrameworkElement)border, value), MultiImageRemove_Click);
                }
                image.ContextMenu = menu;

                border.Child = image;
                Images.Children.Add(border);
            }
        }

        private void MultiImageClear_Click(object sender, RoutedEventArgs e)
        {
            _value.Clear();
            if (Images.Children.Count > 0)
            {
                Images.Children.Clear();
                ChangeField();
            }
        }

        private void ShowImage(byte[] data)
        {
            var filename = Path.ChangeExtension(Path.GetTempFileName(), ".jpg");
            File.WriteAllBytes(filename, data);

            var gsProcessInfo = new ProcessStartInfo();
            gsProcessInfo.Verb = "open";
            gsProcessInfo.WindowStyle = ProcessWindowStyle.Normal;
            gsProcessInfo.FileName = filename;
            gsProcessInfo.UseShellExecute = true;
            Process.Start(gsProcessInfo);
        }

        private void MultiImageView_Click(DFLayoutEmbeddedMediaValue element)
        {
            if (element.Data?.Any() == true)
            {
                ShowImage(element.Data);
            }
            else
            {
                DigitalFormDocumentFactory.LoadDocument(element.ID, (data) =>
                {
                    element.Data = data;
                    Dispatcher.BeginInvoke(() => ShowImage(data));
                });
            }
        }
        private void MultiImageRemove_Click((FrameworkElement, DFLayoutEmbeddedMediaValue) element)
        {
            _value.Remove(element.Item2);
            Images.Children.Remove(element.Item1);
            ChangeField();
        }
        private void MultiImageAdd_Click(object sender, RoutedEventArgs e)
        {
            if (EmbeddedImageUtilities.SelectImageFile(out var data))
            {
                AddMultiImage(new DFLayoutEmbeddedMediaValue { Data = data });
                ChangeField();
            }
        }

        public override DFLayoutEmbeddedMediaValues GetSerializedValue()
        {
            foreach (var val in _value)
            {
                if ((val.Data?.Any() == true) && (val.ID == Guid.Empty))
                    val.ID = DigitalFormDocumentFactory.SaveDocument(val.Data);
            }
            return _value;
        }

        public override void SetSerializedValue(DFLayoutEmbeddedMediaValues value)
        {
            Images.Children.Clear();

            _value = new DFLayoutEmbeddedMediaValues();
            foreach (var val in value)
            {
                AddMultiImage(val);
            }
        }

        public override List<Guid> GetValue()
        {
            return _value.Select(x => x.ID).ToList();
        }

        public override void SetValue(List<Guid>? value)
        {
            var newValue = new DFLayoutEmbeddedMediaValues();
            if(value is not null)
            {
                foreach (var id in value)
                {
                    newValue.Add(new DFLayoutEmbeddedMediaValue
                    {
                        ID = id
                    });
                }
            }
            SetSerializedValue(newValue);
        }

        protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
        {
            base.OnPropertyChanged(e);
            if (e.Property == IsEnabledProperty)
            {
                Grid.RowDefinitions[1].Height = (bool)e.NewValue
                    ? GridLength.Auto
                    : new GridLength(0);
            }
        }
        protected override bool IsEmpty() => _value.Values.Length == 0;
    }
}
