using BuechermarktClient.Models;
using System.ComponentModel;
using System.Linq;
using System.Windows;
using MongoDB.Driver;
using MongoDB.Bson;
using System.Collections.Generic;
using System.Windows.Data;
using System;
using System.Globalization;
using System.Threading;
using System.Windows.Input;
using System.Windows.Controls;
using System.Collections.Specialized;
using System.Collections.ObjectModel;

namespace BuechermarktClient
{


   /// <summary>
   /// Interaktionslogik für Sell.xaml
   /// </summary>
   public partial class Sell : Window, INotifyPropertyChanged
   {

      public event PropertyChangedEventHandler PropertyChanged;
      protected void OnPropertyChanged(string propertyName)
      {
         PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
      }

      private Dictionary<char, char> _Dictionary;
      private Dictionary<char, char> _ReverseDictionary;

      private string _AddField;
      public string AddField
      {
         get
         {
            return _AddField;
         }

         set
         {
            if(value != _AddField)
            {
               _AddField = value;
               OnPropertyChanged("AddField");
            }
         }
      }

      private int _SvSum;
      public int SvSum
      {
         get
         {
            return _SvSum;
         }
         set
         {
            if (value != _SvSum)
            {
               _SvSum = value;
               OnPropertyChanged("SvSum");
            }
         }
      }

      private double _TotalSum;
      public double TotalSum
      {
         get
         {
            return _TotalSum;
         }
         set
         {
            if(value != _TotalSum)
            {
               _TotalSum = value;
               OnPropertyChanged("TotalSum");
            }
         }
      }

      private readonly ObservableCollection<SellBook> _SellBooks;


      public ObservableCollection<SellBook> SellBooks { get { return _SellBooks; } }

      private void listChanged(object sender, NotifyCollectionChangedEventArgs args)
      {
         SvSum = SellBooks.Count;
         var pr = 0.0;
         foreach(var sb in SellBooks)
         {
            pr += sb.Price;
         }
         TotalSum = SvSum + pr;
      }

      public Sell()
      {
         InitializeComponent();
         DataContext = this;
         _SellBooks = new ObservableCollection<SellBook>();
         _SellBooks.CollectionChanged += listChanged;
         _Dictionary = new Dictionary<char, char>();
         _Dictionary.Add('a', 'A');
         _Dictionary.Add('b', 'B');
         _Dictionary.Add('c', 'C');
         _Dictionary.Add('d', 'D');
         _Dictionary.Add('e', 'E');
         _Dictionary.Add('f', 'F');
         _Dictionary.Add('g', 'G');
         _Dictionary.Add('h', 'H');
         _Dictionary.Add('i', 'I');
         _Dictionary.Add('j', 'J');
         _Dictionary.Add('k', 'K');
         _Dictionary.Add('l', 'L');
         _Dictionary.Add('m', 'M');
         _Dictionary.Add('n', 'N');
         _Dictionary.Add('o', 'O');
         _Dictionary.Add('p', 'P');
         _Dictionary.Add('q', 'Q');
         _Dictionary.Add('r', 'R');
         _Dictionary.Add('s', 'S');
         _Dictionary.Add('t', 'T');
         _Dictionary.Add('u', 'U');
         _Dictionary.Add('v', 'V');
         _Dictionary.Add('w', 'W');
         _Dictionary.Add('x', 'X');
         _Dictionary.Add('y', 'Y');
         _Dictionary.Add('z', 'Z');
         _Dictionary.Add('1', '!');
         _Dictionary.Add('2', '"');
         _Dictionary.Add('3', '§');
         _Dictionary.Add('4', '$');
         _Dictionary.Add('5', '%');
         _Dictionary.Add('6', '&');
         _Dictionary.Add('7', '/');
         _Dictionary.Add('8', '(');
         _Dictionary.Add('9', ')');
         _Dictionary.Add('0', '=');
         _Dictionary.Add('ß', '?');
         _Dictionary.Add('-', '_');

         _ReverseDictionary = new Dictionary<char, char>();
         foreach(var entry in _Dictionary)
         {
            _ReverseDictionary.Add(entry.Value, entry.Key);
         }
      }

      private void Add_Click(object sender, RoutedEventArgs e)
      {
         while (true)
         {
            try
            {
               var reverse = ReverseString(AddField);
               var case1 = ReverseUnderscore(AddField);
               var case2 = ReverseUnderscore(reverse);
               foreach (var s in SellBooks)
               {
                  if(s.LabelId == AddField || s.LabelId == reverse || s.LabelId == case1 ||s.LabelId == case2)
                  {
                     MessageBox.Show("Das Buch ist bereits in der Liste");
                     return;
                  }
               }

               var item = MainWindow.BookCollection.FindSync<Models.Book>(b => b.LabelId == AddField || b.LabelId == reverse || b.LabelId == case1 || b.LabelId == case2).FirstOrDefault();
               if (item == null)
               {
                  MessageBox.Show("Das Buch ist nicht vorhanden bitte überprüfen");
                  return;
               }

               var stud = MainWindow.StudentCollection.FindSync<Models.Student>(s => s.ID == item.Student).FirstOrDefault();
               if (stud == null)
               {
                  MessageBox.Show("Der Schüler ist nicht vorhanden bitte überprüfen");
                  return;
               }

               var type = MainWindow.BookTypeCollection.FindSync<Models.BookType>(bt => bt.ID == item.BookType).FirstOrDefault();
               if (type == null)
               {
                  MessageBox.Show("Der Buchtyp (ObjId: " + item.BookType + ") ist nicht vorhanden bitte überprüfen");
                  return;
               }

               var sb = new SellBook();
               sb.StudentId = stud.LabelId;
               sb.LabelId = item.LabelId;
               sb.Price = item.Price;
               sb.Type = type.Name;

               AddField = String.Empty;

               SellBooks.Add(sb);
               Dispatcher.BeginInvoke(new Action(delegate () {
                  BooksList.ItemsSource = SellBooks;
               }));
               return;
            } catch (MongoExecutionTimeoutException)
            {
               Thread.Sleep(100);
            }
         }
      }

      private void ListViewItem_PreviewMouseUp(object sender, MouseButtonEventArgs e)
      {
         if (sender is ListViewItem item && item.IsSelected)
         {
            SellBooks.Remove(item.DataContext as SellBook);
            Dispatcher.BeginInvoke(new Action(delegate () {
               BooksList.ItemsSource = SellBooks;
            }));
         }
      }

      private void SellAll_Click(object sender, RoutedEventArgs e)
      {
         while (true)
         {
            try
            {
               foreach (var sb in SellBooks)
               {
                  MainWindow.BookCollection.FindOneAndUpdate<Models.Book>(b => b.LabelId == sb.LabelId, Builders<Book>.Update.Set(b => b.State, Models.BookState.Selled));
               }
               SellBooks.Clear();
               Dispatcher.BeginInvoke(new Action(delegate () {
                  BooksList.ItemsSource = SellBooks;
               }));
               return;
            } catch (MongoExecutionTimeoutException)
            {
               Thread.Sleep(100);
            }
         }
      }

      private string ReverseString(string s)
      {
         var res = String.Empty;
         foreach(var i in s)
         {
            char v;
            if(_Dictionary.TryGetValue(i, out v) || _ReverseDictionary.TryGetValue(i, out v))
            {
               res += v;
            } else {
               MessageBox.Show(string.Format("Das Label enthält ungültige Zeichen ( {0} ), {1}", i, s));
               return null;
            }
         }
         return res;
      }

      private string ReverseUnderscore(string s)
      {
         if(s.IndexOf("_") >= 0 || s.IndexOf("-") >= 0)
         {
            s = s.Replace("_", "?").Replace("-", "ß");
         } else
         {
            s = s.Replace("?", "_").Replace("ß", "-");
         }
         return s;
      }
   }

   public class SellBook
   {
      public string StudentId { get; set; }
      public string LabelId { get; set; }
      public string Type { get; set; }
      public double Price { get; set; }
   }
}