using System;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Threading;
using System.Threading.Tasks;
using System.Xml.Linq;
using Http.Core.Contexts;
using PCUT.Extensions;
using PCUT.Factories;
using PCUT.ViewModels;
using Windows.UI.Xaml;
using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Input;
using Windows.UI.Xaml.Media.Imaging;
using Windows.UI.Xaml.Navigation;

// The Blank Page item template is documented at https://go.microsoft.com/fwlink/?LinkId=234238

namespace PCUT.Pages
{
    /// <summary>
    /// An empty page that can be used on its own or navigated to within a Frame.
    /// </summary>
    public sealed partial class EditPage : Page
    {
        private SvgData _svgData => SvgData.Instance;
        private LoadingModel LoadingModel { get; set; }
        public ImageViewModel PreviewModel { get; set; }
        public ComponentImageModel ComponentModel { get; set; }
        private DesignCenterViewModel _designCenterModel;

        public EditPage()
        {
            this.InitializeComponent();
            LoadingModel = new LoadingModel();
            PreviewModel = new ImageViewModel();
            ComponentModel = new ComponentImageModel();
            LoadingModel.PropertyChanged += AllImageLoaded;
        }

        protected override async void OnNavigatedTo(NavigationEventArgs e)
        {
            _designCenterModel = e.Parameter as DesignCenterViewModel;
            _designCenterModel.UseOrigin = true;
            if (_svgData.Data != null && _designCenterModel != null && _svgData.FileId != _designCenterModel?.FileId)
                _svgData.SetData(null);

            int dataUnloaded = 0;
            if (_svgData.Data == null)
            {
                if (_designCenterModel == null)
                {
                    _svgData.SetData(null);
                    return;
                }
                dataUnloaded = 1;
                XDocument data; double width; double height;
                using (var fileStream = await FileFactory.GetFileAsync(_designCenterModel.FileId))
                {
                    if (fileStream == null)
                    {
                        LoadingRing.IsActive = false;
                        LoadingRing.Visibility = Visibility.Collapsed;
                        await ShowDialog("File Error!", "File has been deleted or its data was corrupted!\nPlease contact admin to re-upload the file");
                        return;
                    }
                    (data, width, height) = await FileFactory.PreProcessSvgAsync(fileStream);
                }
                var components = data.SplitDocument(width, height).ToArray();
                data.Root.Add(XElement.Parse($"<rect id=\"PCUT_BOUNDING\" x=\"0\" y=\"0\" width=\"{width}\" height=\"{height}\" fill=\"none\" stroke=\"black\" stroke-dasharray=\"{width / 200}\" stroke-width=\"{width / 2000}\" />"));

                _svgData.SetData(data, width, height);
                _svgData.ItemId = _designCenterModel.ItemId;
                _svgData.FileId = _designCenterModel.FileId;
                foreach (var (id, deleted, component, boundWidth, boundHeight) in components)
                    _svgData.AddComponent(id, deleted, component, boundWidth, boundHeight);
            }

            if (UserContext.Instance.IsPermittedEdit)
            {
                _designCenterModel.Width = _svgData.OriginWidth.Value;
                _designCenterModel.Height = _svgData.OriginHeight.Value;
            }
            _designCenterModel.PropertyChanged += UpdateSizeChanged;

            if (_svgData.Data != null)
            {
                LoadingModel.SetCount(_svgData.ComponentCount + dataUnloaded);
                PreviewModel.SetSource(_svgData.Data, Image_Loaded);
                foreach (var (id, deleted, component) in _svgData.ComponentData)
                    ComponentModel.AddSource(id, deleted, component, Image_Loaded);
            }
            if (!UserContext.Instance.IsPermittedEdit)
                _designCenterModel.SelectedHeightIndex = 0;
        }

        protected override void OnNavigatedFrom(NavigationEventArgs e)
        {
            //if (e.SourcePageType != typeof(SvgNestPage))
            //    _svgData.SetData(null);

            if (_designCenterModel != null)
                _designCenterModel.PropertyChanged -= UpdateSizeChanged;
        }

        private static readonly object _boundingSizeLock = new object();
        private void UpdateSizeChanged(object sender, PropertyChangedEventArgs e)
        {
            if (e.PropertyName == nameof(DesignCenterViewModel.Width))
            {
                var width = (sender as DesignCenterViewModel).Width;
                _svgData.SetResult(null);
                _designCenterModel.MinSize = 0;
                _ = HandleSizeChangedAsync(width: width);
            }
            else if (e.PropertyName == nameof(DesignCenterViewModel.Height))
            {
                var height = (sender as DesignCenterViewModel).Height;
                _svgData.SetResult(null);
                _designCenterModel.MinSize = 0;
                _ = HandleSizeChangedAsync(height: height);
            }
        }

        private async Task HandleSizeChangedAsync(double? width = null, double? height = null)
        {
            if (Monitor.TryEnter(_boundingSizeLock, 100))
            {
                try
                {
                    var bound = _svgData.Data.GetDescendantById("PCUT_BOUNDING");
                    if (width != null)
                    {
                        bound.SetAttributeValue("width", width.Value);
                    }
                    if (height != null)
                    {
                        bound.SetAttributeValue("height", height.Value);
                    }
                    _svgData.CleanUpContext();
                    await PreviewModel.Source.LoadSvgAsync(_svgData.Data);
                }
                finally
                {
                    Monitor.Exit(_boundingSizeLock);
                }
            }
        }

        private void MainScroll_Loading(FrameworkElement sender, object args)
        {
            ((ComponentStyle)Resources["previewStyle"]).SetSize(PreviewRowDefinition, PreviewColumnDefinition);
        }

        private void ComponentPreview_Loading(FrameworkElement sender, object args)
        {
            ((ComponentStyle)Resources["componentStyle"]).SetSize(ComponentColumnDefinition, rate: 3);
        }

        private void Image_Loaded(SvgImageSource sender, SvgImageSourceOpenedEventArgs e)
        {
            LoadingModel.DecreaseCount();
            sender.Opened -= Image_Loaded;
        }

        private void AllImageLoaded(object sender, PropertyChangedEventArgs e)
        {
            LoadingRing.IsActive = false;
            LoadingRing.Visibility = Visibility.Collapsed;
        }

        private void MainScroll_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
        {
            var (offsetX, offsetY) = e.Delta.CalculateTranslation(e.Velocities);
            var scrollViewer = sender as ScrollViewer;
            _ = scrollViewer.ChangeView(scrollViewer.HorizontalOffset - offsetX, scrollViewer.VerticalOffset - offsetY, scrollViewer.ZoomFactor);
        }

        private void MainPreviewRefresh_Click(object sender, RoutedEventArgs e)
        {
            MainScroll.ChangeView(0, 0, 1);
        }

        private void MainPreviewSelectAll_Click(object sender, RoutedEventArgs e)
        {
            foreach (var component in ComponentModel.ComponentList.Where(x => x.Deleted))
            {
                _svgData.Data.RestoreById(component.Id);
                component.Deleted = false;
            }
            PreviewModel.SetSource(_svgData.Data);
        }

        private void MainPreviewDeleteAll_Click(object sender, RoutedEventArgs e)
        {
            foreach (var component in ComponentModel.ComponentList.Where(x => !x.Deleted))
            {
                _svgData.Data.HideById(component.Id);
                component.Deleted = true;
            }
            PreviewModel.SetSource(_svgData.Data);
        }

        private void Image_Tapped(object sender, TappedRoutedEventArgs e)
        {
            var image = (sender as FrameworkElement);
            var id = image.Tag as string;

            var component = ComponentModel.ComponentList.FirstOrDefault(x => x.Id == id);
            if (component == null)
                return;

            if (component.Deleted)
                RestoreComponent(id, component);
            else
                DeleteComponent(id, component);
        }

        private void ComponentDelete(object sender, RoutedEventArgs e)
        {
            var item = sender as FrameworkElement;
            var id = item.Tag as string;

            DeleteComponent(id, item.DataContext as ComponentImageSource);
        }

        private void ComponentRestore(object sender, RoutedEventArgs e)
        {
            var item = sender as FrameworkElement;
            var id = item.Tag as string;

            RestoreComponent(id, item.DataContext as ComponentImageSource);
        }

        private void DeleteComponent(string id, ComponentImageSource component)
        {
            if (component == null) return;
            _svgData.Data.HideById(id);
            component.Deleted = true;
            PreviewModel.SetSource(_svgData.Data);
        }

        private void RestoreComponent(string id, ComponentImageSource component)
        {
            if (component == null) return;
            _svgData.Data.RestoreById(id);
            component.Deleted = false;
            PreviewModel.SetSource(_svgData.Data);
        }

        private async Task ShowDialog(string title, string content)
        {
            ContentDialog dialog = new ContentDialog
            {
                Title = title,
                Content = content,
                CloseButtonText = "OK"
            };
            dialog.CloseButtonStyle = Application.Current.Resources["CloseDialogButton"] as Style;

            await dialog.ShowAsync();
        }
    }
}
