using ChatController.ChatKlassen;
using Newtonsoft.Json;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;
using System.Threading;
using System.Web;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Forms;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using ChatController.Core;
using ChatController.Extensions;
using ChatController.LoginKlassen;
using ChatController.Utilities;
using ChatController.Utilities.Extensions;
using RestSharp;
using RestSharp.Extensions;
using Clipboard = System.Windows.Forms.Clipboard;
using ContextMenu = System.Windows.Controls.ContextMenu;
using DataFormats = System.Windows.Forms.DataFormats;
using Image = System.Drawing.Image;
using MessageBox = System.Windows.MessageBox;

namespace ChatController.HauptKlassen
{
    // Ist quasi das ViewModel
    public class Chat
    {
        public Action<Exception> ExceptionCallback { get; set; }
        public Action<Exception> ThreadExceptionCallback { get; set; }

        private readonly List<Contact> _Contacts = new List<Contact>();

        public static ChatDatenUebergabe ChatDaten { get; set; }

        private UserMessages _UserMessages;
        private UserMessages _AdditionalUserMessages;

        private string _NextPage;
        private bool _HasNextPage;

        public long LastTimeStamp { get; set; }

        public Chat(ChatDatenUebergabe chatDaten, Action<Exception> exceptionCallback, Action<Exception> threadExceptionCallback)
        {
            ChatDaten = chatDaten;
            ExceptionCallback = exceptionCallback;
            ThreadExceptionCallback = threadExceptionCallback;

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            PinCertificate();
        }

        private static void PinCertificate()
        {
            ServicePointManager.ServerCertificateValidationCallback = PinPublicKey;
        }

        private static bool PinPublicKey(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslpolicyerrors)
        {
            try
            {
                if(certificate == null || chain == null)
                {
                    return false;
                }

                var chainContainsPk = false;

                foreach(var element in chain.ChainElements)
                {
                    var pk = element.Certificate.GetPublicKeyString();
                    if(pk == PubKeyX3 || pk == PubKeyR3 || pk == PubKeyE1)
                    {
                        chainContainsPk = true;
                    }
                }

                var subjectAccepted = certificate.Subject.Trim().ToLower().EndsWith(".bewoplaner.de") || certificate.Subject.Trim().ToLower().EndsWith(".ownchat.de");

                return chainContainsPk && subjectAccepted;
            }
            catch(Exception)
            {
                return false;
            }
        }

        private const string PubKeyX3 = "3082010A02820101009CD30CF05AE52E47B7725D3783B3686330EAD735261925E1BDBE35F170922FB7B84B4105ABA99E350858ECB12AC468870BA3E375E4E6F3A76271BA7981601FD7919A9FF3D0786771C8690E9591CFFEE699E9603C48CC7ECA4D7712249D471B5AEBB9EC1E37001C9CAC7BA705EACE4AEBBD41E53698B9CBFD6D3C9668DF232A42900C867467C87FA59AB8526114133F65E98287CBDBFA0E56F68689F3853F9786AFB0DC1AEF6B0D95167DC42BA065B299043675806BAC4AF31B9049782FA2964F2A20252904C674C0D031CD8F31389516BAA833B843F1B11FC3307FA27931133D2D36F8E3FCF2336AB93931C5AFC48D0D1D641633AAFA8429B6D40BC0D87DC3930203010001";

        private const string PubKeyR3 = "3082010A0282010100BB021528CCF6A094D30F12EC8D5592C3F882F199A67A4288A75D26AAB52BB9C54CB1AF8E6BF975C8A3D70F4794145535578C9EA8A23919F5823C42A94E6EF53BC32EDB8DC0B05CF35938E7EDCF69F05A0B1BBEC094242587FA3771B313E71CACE19BEFDBE43B45524596A9C153CE34C852EEB5AEED8FDE6070E2A554ABB66D0E97A540346B2BD3BC66EB66347CFA6B8B8F572999F830175DBA726FFB81C5ADD286583D17C7E709BBF12BF786DCC1DA715DD446E3CCAD25C188BC60677566B3F118F7A25CE653FF3A88B647A5FF1318EA9809773F9D53F9CF01E5F5A6701714AF63A4FF99B3939DDC53A706FE48851DA169AE2575BB13CC5203F5ED51A18BDB150203010001";

        private const string PubKeyE1 = "04245C2DA22AFD1C4BA65D97732731ACB2A06962EF65E8A6B0F0AC4B9FFF1C0B700FD3982F4DFC0F009B37F074055732972E05EF2A4325A3FB6E342713F64F7E69D302995EEB244792C1249BE6B1218FC12481FC68CC1F69BA58F51922F774C616";

        public List<Contact> AddContacts()
        {
            var groupInputs = ChatDaten?.AlleGruppen?.Response?.Groups?.ToArray() ?? new GroupInput[0];
            _Contacts.AddRange(GenerateContactsFromServerResponse(groupInputs, true));

            return _Contacts;
        }

        // Klick auf Kontakt. Die Collection muss davor geleert werden.
        // Führt zu doppelter neuester Nachricht, wenn man vorher eine verschickt hat!
        public void LoadChatMessagesForContactAsync(Contact contact, ChatMessage previousMessage, Action<List<ChatMessage>> callback)
        {
            if(!(contact is null))
            {
                LoadMessagesFromServerAsync(contact.GroupId, delegate
                {
                    callback?.Invoke(AddMessagesFromServerResponse(_UserMessages.Response.Messages, previousMessage));
                });

                return;
            }

            callback?.Invoke(new List<ChatMessage>());
        }

        private void LoadMessagesFromServerAsync(long groupId, Action callback)
        {
            try
            {
                var url = $"{ChatDaten.ServerUrl}{Constants.LoadMessagesForGroupUrl}{groupId}";

                var client = new RestClient(url);
                var request = new RestRequest();

                request.AddHeader(Constants.Token, ChatDaten.AuthToken);
                request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

                client.ExecuteAsync(request, response =>
                {
                    _UserMessages = JsonConvert.DeserializeObject<UserMessages>(response.Content);
                    
                    if (_UserMessages?.Response?.HasMorePages ?? false)
                    {
                        _NextPage = _UserMessages.Response.NextPage;
                        _HasNextPage = true;
                    }
                    else
                    {
                        _HasNextPage = false;
                    }

                    callback?.Invoke();
                });
            }
            catch (Exception exception)
            {
                ThreadExceptionCallback?.Invoke(exception);
            }
        }

        public void LoadMoreMessagesAsync(Contact contact, ChatMessage previousMessage, Action<List<ChatMessage>> callback)
        {
            LoadMoreMessagesFromServerAsync(contact.GroupId, _NextPage, () =>
            {
                callback?.Invoke(AddMessagesFromServerResponse(_AdditionalUserMessages?.Response.Messages ?? new Messages[0], previousMessage));
            });
        }

        private void LoadMoreMessagesFromServerAsync(long groupId, string page, Action callback)
        {
            try
            {
                if(page is null || !page.Contains("="))
                {
                    callback?.Invoke();
                    return;
                }

                var pageParam = page.Split('=')[1];

                var url = $"{ChatDaten.ServerUrl}/api/chat/messages?groupid={groupId}&page={pageParam}";

                var client = new RestClient(url);
                var request = new RestRequest();

                request.AddHeader(Constants.Token, ChatDaten.AuthToken);
                request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

                client.ExecuteAsync(request, response =>
                {
                    _AdditionalUserMessages = null;
                    _AdditionalUserMessages = JsonConvert.DeserializeObject<UserMessages>(response.Content);

                    if (_AdditionalUserMessages?.Response?.HasMorePages ?? false)
                    {
                        _NextPage = _AdditionalUserMessages.Response.NextPage;
                    }

                    _HasNextPage = _AdditionalUserMessages?.Response?.HasMorePages ?? false;

                    callback?.Invoke();
                });
            }
            catch(Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        private double _FormerMessagesCount;

        public void CheckIfNewMessagesExistAsync(long groupId, Action<bool> callback)
        {
            var span = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            var timespan = Convert.ToInt64(span.TotalSeconds);

            if (_UserMessages != null && _UserMessages.Response.Messages.Length > 0)
            {
                timespan = _UserMessages.Response.Messages.First().Created_At;
            }

            GetNumberOfNewMessagesAsync(groupId, timespan, numberOfNewMessages =>
            {
                var hasNewMessages = numberOfNewMessages != _FormerMessagesCount;

                _FormerMessagesCount = numberOfNewMessages;

                callback?.Invoke(hasNewMessages);
            });
        }

        private void GetNumberOfNewMessagesAsync(long groupId, long lastTimeStamp, Action<double> callback)
        {
            try
            {
                var url = $"{ChatDaten.ServerUrl}{Constants.LoadOwnChatNewsUrl}{groupId}/{lastTimeStamp}";

                var client = new RestClient(url);
                var request = new RestRequest();

                request.AddHeader(Constants.Token, ChatDaten.AuthToken);
                request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

                client.ExecuteAsync(request, response =>
                {
                    var messageCounter = JsonConvert.DeserializeObject<MessageCounter>(response.Content);

                    callback?.Invoke(messageCounter?.MessageCount ?? 0);
                });
            }
            catch(Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
                callback?.Invoke(0d);
            }
        }

        public void GetNumberOfAllNewMessagesAsync(Action<double> callback)
        {
            LoadNumberOfNewMessagesFromServerAsync(0, numberOfNewMessages =>
            {
                if(numberOfNewMessages > 0)
                {
                    LastTimeStamp = DateTime.UtcNow.GetUnixTimeStamp();
                }

                callback?.Invoke(numberOfNewMessages);
            });
        }

        private void LoadNumberOfNewMessagesFromServerAsync(long groupId, Action<double> callback)
        {
            try
            {
                var url = $"{ChatDaten.ServerUrl}{Constants.LoadOwnChatNewsUrl}{groupId}/{LastTimeStamp}";

                var client = new RestClient(url);
                var request = new RestRequest();

                request.AddHeader(Constants.Token, ChatDaten.AuthToken);
                request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

                client.ExecuteAsync(request, response =>
                {
                    var messageCounter = JsonConvert.DeserializeObject<MessageCounter>(response.Content);

                    callback?.Invoke(messageCounter?.MessageCount ?? 0);
                });
            }
            catch(Exception exception)
            {
                ThreadExceptionCallback?.Invoke(exception);
            }
        }

        private void LoadGroupsAsync(Action<ChatGruppenDaten> callback)
        {
            try
            {
                var url = $"{ChatDaten.ServerUrl}{Constants.GetChatGroupsUrl}";

                var client = new RestClient(url);
                var request = new RestRequest();

                request.AddHeader(Constants.Token, ChatDaten.AuthToken);
                request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

                client.ExecuteAsync(request, response =>
                {
                    var contacts = JsonConvert.DeserializeObject<ChatGruppenDaten>(response.Content);

                    callback?.Invoke(contacts);
                });
            }
            catch(Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public void UpdateContactList(Action<IOrderedEnumerable<Contact>> callback)
        {
            try
            {
                LoadGroupsAsync(rawData =>
                {
                    var contacts = GenerateContactsFromServerResponse(rawData.Response.Groups.ToArray(), true);

                    callback?.Invoke(contacts.OrderByDescending(c => c.TimeStamp));
                });
            }
            catch(Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public List<ChatMessage> AddNewMessage(string pMessage, long pGroupId, ChatMessage previousMessage)
        {
            var result = new List<ChatMessage>();

            try
            {
                var time = DateTime.Now;

                var chatMessage = new ChatMessage(pGroupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, pMessage, time, true, 0, null, null, null, null, null, ChatMessageType.Message, ChatDaten.LoggedInUser.Response.User.Oid);
                result.Add(chatMessage);

                return AddSeparators(result);
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }

            return result;
        }

        // ToDo: Funktioniert nicht mit der Version von RestSharp, die mit .NET Version 4.5 kompatibel ist
        public void SendMessageAsync(string message, long groupId)
        {
            try
            {
                var url = ChatDaten.ServerUrl + Constants.SendMessageUrl;
                var requestBody = $"{HttpUtility.UrlEncode("groupid")}={HttpUtility.UrlEncode(groupId.ToString())}&{HttpUtility.UrlEncode("text")}={HttpUtility.UrlEncode(message)}";
                var client = new RestClient(url);
                var request = new RestRequest(Method.POST);

                request.AddHeader(Constants.ContentTypeKey, Constants.MultipartContentTypeValue);
                request.AddParameter(Constants.Token, ChatDaten.AuthToken);
                request.AddParameter(Constants.CustomerId, ChatDaten.Kundennummer);

                request.AddParameter(Constants.MultipartContentTypeValue, requestBody, ParameterType.RequestBody);

                client.PostAsync(request, (response, handle) =>
                {

                });

                /*
                 *
                    multiPartContent.Add(new StringContent(groupId.ToString()), "groupid");
                    multiPartContent.Add(new StringContent(message), "text");
                    
                    //wegen Kontent nachschauen 
                    httpRequest.Content = multiPartContent;

                    httpRequest.Headers.Add("Token", ChatDaten.AuthToken);
                    httpRequest.Headers.Add("CustomerID", ChatDaten.Kundennummer);

                    ---------------------------------------------------------------------------------------------------------------------------------------------------

                    var url = _BaseUrl + Constants.LoginWithChatCodeUrl;
                    var requestBody = $"{HttpUtility.UrlEncode("username")}={HttpUtility.UrlEncode(_UserName)}&{HttpUtility.UrlEncode("password")}={HttpUtility.UrlEncode(_Password)}&{HttpUtility.UrlEncode("chatcode")}={HttpUtility.UrlEncode(_ChatCode)}";

                    var client = new RestClient(url);
                    var request = new RestRequest(Method.POST);

                    request.AddHeader(Constants.ContentTypeKey, Constants.FormUrlEncodedContentTypeValue);
                    request.AddParameter(Constants.CustomerId, _Tenant, ParameterType.HttpHeader);
                    request.AddParameter(Constants.FormUrlEncodedContentTypeValue, requestBody, ParameterType.RequestBody);

                    client.PostAsync(request, (response, handle) =>
                    {
                        Debug.WriteLine(response.Content);

                        var connectionData = JsonConvert.DeserializeObject<UserDaten>(response.Content);

                        if (connectionData.Success)
                        {
                            _AuthToken = connectionData.Response.User.Token;
                            _UserId = connectionData.Response.User.Oid;

                            Utils.AuthToken = _AuthToken;
                            Utils.Tenant = _Tenant;

                            _LoggedInUser = connectionData;

                            callback?.Invoke(true);
                        }
                        else
                        {
                            var errorMessage = string.Empty;

                            if (connectionData.Error?.ChatCodeFailed != null)
                            {
                                errorMessage = $"Fehler: {connectionData.Error.ChatCodeFailed[0]}\nBitte überprüfen Sie die Anmeldeinformationen.";
                            }
                            else if (connectionData.Error?.LoginFailed != null)
                            {
                                errorMessage = $"Fehler: {connectionData.Error.LoginFailed[0]}\nBitte überprüfen Sie die Anmeldeinformationen.";
                            }

                            if (!string.IsNullOrWhiteSpace(errorMessage))
                            {
                                exceptionCallback?.Invoke(errorMessage);
                            }
                        }
                    });
                 */
            }
            catch(Exception exception)
            {
                MessageBox.Show(exception.Message, "Fehler", MessageBoxButton.OK);
            }
        }

        public async void SendMessage(string message, long groupId)
        {
            try
            {
                var endurl = ChatDaten.ServerUrl + Constants.SendMessageUrl;

                using (var multiPartContent = new MultipartFormDataContent())
                {
                    multiPartContent.Add(new StringContent(groupId.ToString()), "groupid");
                    multiPartContent.Add(new StringContent(message), "text");
                    
                    var requestUri = new Uri(endurl);

                    var httpRequest = new HttpRequestMessage {Method = HttpMethod.Post, RequestUri = requestUri, Content = multiPartContent};

                    //wegen Kontent nachschauen 
                    httpRequest.Headers.Add("Token", ChatDaten.AuthToken);
                    httpRequest.Headers.Add("CustomerID", ChatDaten.Kundennummer);

                    var httpClient = new HttpClient();
                    await httpClient.SendAsync(httpRequest, CancellationToken.None).ConfigureAwait(false);
                }
               
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public string OpenFile()
        {
            try
            {
                var openFileDialog = new OpenFileDialog
                {
                    Filter = Resource.OpenFileDialogFilter_Test
                };

                var result = openFileDialog.ShowDialog();
                
                return result == DialogResult.OK ? openFileDialog.FileName : null;
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
                return null;
            }
        }

        public List<ChatMessage> AddNewFile(string pathToFile, string originalFilePath, long groupId, ChatMessage previousMessage)
        {
            var result = new List<ChatMessage>();

            try
            {
                if (string.IsNullOrEmpty(pathToFile) || string.IsNullOrEmpty(originalFilePath))
                {
                    return result;
                }

                var latestMessage = _UserMessages.Response.Messages.Last();

                var sendTime = DateTime.Now;

                if (Constants.ImageFileExtensions.Contains(Path.GetExtension(pathToFile).ToUpperInvariant()))
                {
                    byte[] file;
                    using (Stream reader = File.OpenRead(pathToFile))
                    {
                        file = Utils.ReadFully(reader);
                    }
                    
                    using(var memoryStream = new MemoryStream(file))
                    {
                        var image = Image.FromStream(memoryStream);

                        using (var bitmap = new Bitmap(image))
                        {
                            using (var stream = new MemoryStream())
                            {
                                short orient = 0;
                                const int orientationId = 0x0112;

                                if (image.PropertyIdList.Contains(orientationId))
                                {
                                    var item = image.GetPropertyItem(orientationId);

                                    orient = BitConverter.ToInt16(item.Value, 0);
                                
                                    bitmap.SetPropertyItem(item);
                                }

                                var flipType = Utils.OrientationToFlipType(orient.ToString());

                                bitmap.RotateFlip(flipType); 

                                bitmap.Save(stream, ImageFormat.Jpeg);


                                var bitmapImage = new BitmapImage();

                                bitmapImage.BeginInit();
                                bitmapImage.StreamSource = new MemoryStream(stream.ToArray());
                                bitmapImage.EndInit();
                                bitmapImage.Freeze();

                                var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(pathToFile), sendTime, true, memoryStream.Length, null, pathToFile, Path.GetFileName(pathToFile), null, bitmapImage, ChatMessageType.Image, ChatDaten.LoggedInUser.Response.User.Oid);
                                result.Add(chatMessage);
                            }
                        }
                    }
                }
                else
                {
                    var linkToThumbnail = $"{ChatDaten.ServerUrl}/document.png";

                    var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(pathToFile), sendTime, true, 0, pathToFile, null, null, linkToThumbnail, null, ChatMessageType.Document, ChatDaten.LoggedInUser.Response.User.Oid);
                    result.Add(chatMessage);
                }

                return AddSeparators(result);
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }

            return result;
        }

        public List<ChatMessage> AddFileToMessage(byte[] file, string fileName, long groupId, ChatMessage previousMessage)
        {
            var result = new List<ChatMessage>();

            if (string.IsNullOrEmpty(fileName))
            {
                return result;
            }

            if(previousMessage != null)
            {
                result.Add(previousMessage);
            }

            var message = _UserMessages.Response.Messages.Last();

            var sendtime = DateTime.Now;

            if (Constants.ImageFileExtensions.Contains(Path.GetExtension(fileName).ToUpperInvariant()))
            {
                var bitmapImage = new BitmapImage();
                var memoryStream = new MemoryStream(file);
                
                bitmapImage.BeginInit();
                bitmapImage.StreamSource = memoryStream;
                bitmapImage.EndInit();
                bitmapImage.Freeze();

                memoryStream.Close();
                ImageSource logo = bitmapImage;

                // Mit Logo
                var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(fileName), sendtime, true, memoryStream.Length, null, fileName, Path.GetFileName(fileName), null, logo, ChatMessageType.Image, ChatDaten.LoggedInUser.Response.User.Oid);

                result.Add(chatMessage);
            }
            else 
            {
                // Dokument
                var chatMessage = new ChatMessage(groupId, 0, ChatDaten.LoggedInUser.Response.User.UserName, Path.GetFileName(fileName), sendtime, true, 0, fileName, null, null, message.Smaller_Image, null, ChatMessageType.Document, ChatDaten.LoggedInUser.Response.User.Oid);
                result.Add(chatMessage);
            }

            return AddSeparators(result);
        }

        public void SendFileToContact(Contact currentContact, string pFile, string pOriginalFilePath)
        {
            try
            {             
                SendFile(pFile, currentContact, pOriginalFilePath);   
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        // WebRequest                                                                                                                                                                            
        private void SendFile(string pFile, Contact currentContact, string pOriginalFilePath)
        {
            if(string.IsNullOrEmpty(pOriginalFilePath))
            {
                return;
            }

            byte[] mediaFile;
            using (Stream reader = File.OpenRead(pFile))
            {
                mediaFile = Utils.ReadFully(reader);
            }
            
            var fileName = Path.GetFileName(pOriginalFilePath).ToLower();

            if (Constants.ImageFileExtensions.Contains(Path.GetExtension(fileName).ToUpperInvariant()))
            { 
                fileName = fileName.Replace(".bmp", ".jpg");

                SendMediaMessage(fileName, currentContact.GroupId, mediaFile);
            }
            else
            {
                SendMediaMessage(fileName, currentContact.GroupId, mediaFile);
            }
        }
        
        private HttpRequestMessage _HttpRequest;

        // WebRequest
        private async void SendMediaMessage(string pMessage, long pGroupId, byte[] pMediaFile)
        {
            try
            {
                using (var multiPartContent = new MultipartFormDataContent())
                {
                    var requestUri = new Uri(ChatDaten.ServerUrl + Constants.SendMessageUrl);

                    multiPartContent.Add(new ByteArrayContent(pMediaFile, 0, pMediaFile.Length), "file", pMessage);
                    multiPartContent.Add(new StringContent(pGroupId.ToString()), "groupid");

                    _HttpRequest = new HttpRequestMessage
                    {
                        Method = HttpMethod.Post,
                        RequestUri = requestUri,
                        Content = multiPartContent
                    };

                    _HttpRequest.Headers.Add(Constants.Token, ChatDaten.AuthToken);
                    _HttpRequest.Headers.Add(Constants.CustomerId, ChatDaten.Kundennummer);

                    var httpClient = new HttpClient();
                    var httpResponse = await httpClient.SendAsync(_HttpRequest, CancellationToken.None).ConfigureAwait(false);

                    var antwortResponse = await httpResponse.Content.ReadAsStringAsync();
                }
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public ContextMenu ErstelleKontextMenue()
        {
            var contextMenu = new ContextMenu();
            
            var item1 = new System.Windows.Controls.MenuItem();
            var item2 = new System.Windows.Controls.MenuItem();
            var item3 = new System.Windows.Controls.MenuItem();

            contextMenu.Items.Add(item1);
            contextMenu.Items.Add(item2);
            contextMenu.Items.Add(item3);

            item1.Header = "Speichern unter";
            item1.Visibility = Visibility.Visible;
            
            item2.Header = "Einfügen";
            item2.Visibility = Visibility.Visible;

            item3.Header = "Kopieren";
            item3.Visibility = Visibility.Visible;

            return contextMenu;
        }

        public void SaveFileAs(ChatMessage pChatMessage)
        {
            if (pChatMessage.PictureSource != null)
            {
                SaveAs(1, Path.GetFileName(pChatMessage.OriginalImage), DownloadMediaFile(pChatMessage.OriginalImage));
            }
        }

        private byte[] DownloadMediaFile(string pFilePath)
        {
            byte[] mediaFile = null;
            
            try
            {
                using(var webClient = new WebClient())
                {
                    webClient.Credentials = CredentialCache.DefaultCredentials;
                    webClient.Headers[Constants.Token] = ChatDaten.AuthToken;
                    webClient.Headers[Constants.CustomerId] = ChatDaten.Kundennummer;
                    mediaFile = webClient.DownloadData(pFilePath);
                }

                return mediaFile;
            }
            catch(Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
            
            return mediaFile;
        }

        private void SaveAs(int pFilterType, string pFileName, byte[] pMediaFile)
        {
            try
            {
                var saveFileDialog = new SaveFileDialog {FileName = Path.GetFileName(pFileName)};

                switch(pFilterType)
                {
                    case 1:
                        saveFileDialog.Filter = Resource.SaveFileDialogFilter_Images;
                        saveFileDialog.Title = Resource.SaveFIleDialogTitle_Images;
                        saveFileDialog.ShowDialog();
                        break;
                    case 2:
                        saveFileDialog.Filter = Resource.SaveFileDialogFilter_Documents;
                        saveFileDialog.Title = Resource.SaveFIleDialogTitle_Documents;
                        saveFileDialog.ShowDialog();
                        break;
                    case 3:
                        saveFileDialog.Filter = Resource.SaveFileDialogFilter_Audio;
                        saveFileDialog.Title = Resource.SaveFIleDialogTitle_Audio;
                        saveFileDialog.ShowDialog();
                        break;
                }

                if (!string.IsNullOrEmpty(saveFileDialog.FileName))
                {
                    var fileStream = (FileStream)saveFileDialog.OpenFile();

                    fileStream.Write(pMediaFile, 0, pMediaFile.Length);

                    fileStream.Close();
                }
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public void Paste(long pGroupOid, ChatMainControl pChatMainControl)
        {         
            var dataObject = Clipboard.GetDataObject();

            if(dataObject == null)
            {
                return;
            }
            
            if (dataObject.GetDataPresent(DataFormats.FileDrop))
            {
                try
                {
                    if (dataObject.GetData(DataFormats.FileDrop) is string[] fileList)
                    {
                        if (File.Exists(fileList[0]))
                        {
                            var fileName = Path.GetFileName(fileList[0]);
                            
                            var mediaFile = File.ReadAllBytes(fileList[0]);

                            pChatMainControl.AddMessages(AddFileToMessage(mediaFile, fileName, pGroupOid, pChatMainControl.GetFirstMessage()));
                            
                            CollectionViewSource.GetDefaultView(pChatMainControl.ChatListBox.ItemsSource).Refresh();

                            pChatMainControl.ChatListBox.Items.MoveCurrentToLast();
                            pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem);

                            SendMediaMessage(fileName, pGroupOid, mediaFile);
                        }
                    }
                }
                catch (Exception exception)
                {
                    ExceptionCallback?.Invoke(exception);
                }
            }
            else
            {
                if (dataObject.GetDataPresent(DataFormats.Text))
                {
                    var text = (string) dataObject.GetData(DataFormats.StringFormat);

                    pChatMainControl.AddMessages(AddNewMessage(text, pGroupOid, pChatMainControl.GetFirstMessage()));
                
                    CollectionViewSource.GetDefaultView(pChatMainControl.ChatListBox.ItemsSource).Refresh();

                    pChatMainControl.ChatListBox.Items.MoveCurrentToLast();
                    pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem);

                    SendMessage(text, pGroupOid);
                }
                else if (dataObject.GetDataPresent(DataFormats.Bitmap))
                {
                    var bitmap = (Bitmap) dataObject.GetData(DataFormats.Bitmap);

                    var imageName = Utils.GenerateTempName() + ".jpg";

                    Image image = bitmap;

                    pChatMainControl.AddMessages(AddFileToMessage(Utils.ImageToByteArray(image), imageName, pGroupOid, pChatMainControl.GetFirstMessage()));
                        
                    CollectionViewSource.GetDefaultView(pChatMainControl.ChatListBox.ItemsSource).Refresh();

                    pChatMainControl.ChatListBox.Items.MoveCurrentToLast();
                    pChatMainControl.ChatListBox.ScrollIntoView(pChatMainControl.ChatListBox.Items.CurrentItem);

                    SendMediaMessage(imageName, pGroupOid, Utils.ImageToByteArray(image));
                }
                else
                {
                    MessageBox.Show("Der Zwischen-Speicher kann nicht verarbeitet werden.", "Fehler", MessageBoxButton.OK);
                }
            }
        }

        public void Copy(object pData, int pDataType)
        { 
            switch(pDataType)
            {
                case 1:
                    Clipboard.SetData(DataFormats.Text, pData);
                    break;
                case 2:
                    Clipboard.SetData(DataFormats.Bitmap, pData);
                    break;
                case 3:
                    Clipboard.SetData(DataFormats.FileDrop, pData);
                    break;
            }
        }
        
        public void ShowProfilePicture(Contact currentContact)
        {
            try
            {
                ShowPictureWindow(currentContact.Image, currentContact.Name);
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public void ShowPictureWindow(ImageSource imageSource, string title)
        {
            try
            {
                var imageWidth = Convert.ToInt32(imageSource.Width);
                var imageHeight = Convert.ToInt32(imageSource.Height);

                var imageAspectRatio = imageWidth / (double)imageHeight;

                var primaryScreenWidth2 = SystemParameters.PrimaryScreenWidth;
                var primaryScreenHeight2 = SystemParameters.PrimaryScreenHeight;

                var windowMaxWidth = imageWidth;
                var windowMaxHeight = imageHeight;

                if(windowMaxWidth > .8 * primaryScreenWidth2 || windowMaxHeight > .8 * primaryScreenHeight2)
                {
                    if(primaryScreenWidth2 > primaryScreenHeight2)
                    {
                        windowMaxHeight = (int)(.8 * primaryScreenHeight2);
                        windowMaxWidth = (int)(windowMaxHeight * imageAspectRatio);
                    }
                    else
                    {
                        windowMaxWidth = (int)(.8 * primaryScreenWidth2);
                        windowMaxHeight = (int)(windowMaxWidth * imageAspectRatio);
                    }
                }

                var maximumWindowSize = new System.Windows.Size(windowMaxWidth, windowMaxHeight);

                var minHeight = 232 / imageAspectRatio;
                var minWidth = 232d;

                var window = new Window
                {
                    Title = title,
                    MinHeight = minHeight,
                    MinWidth = minWidth
                };

                var grid = new Grid
                {
                    Width = maximumWindowSize.Width,
                    Height = maximumWindowSize.Height,
                    MinHeight = minHeight,
                    MinWidth = minWidth
                };

                var image = new System.Windows.Controls.Image
                {
                    Source = imageSource,
                    Margin = new Thickness(0)
                };

                grid.Children.Clear();
                grid.Children.Add(image);


                window.SizeToContent = SizeToContent.WidthAndHeight;
                window.Content = grid;
                window.Margin = new Thickness(0);
                window.WindowStartupLocation = WindowStartupLocation.CenterScreen;

                window.ShowDialog();
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public void ShowPicture(string originalImage, long groupId, Action<ImageSource, string> downloadCompletedCallback)
        {
            if(originalImage is null)
            {
                return;
            }

            try
            {
                Utils.DownloadImageAsync(originalImage, $"group-{groupId}", CacheCategory.MessageAttachment, imageSource =>
                {
                    var splitName = originalImage.Split('/');
                    var last = splitName.LastOrDefault();

                    downloadCompletedCallback?.Invoke(imageSource, last ?? "Bild");
                });
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }

        public void ReloadGroupsAsync(Action<ChatGruppenDaten> callback)
        {
            var url = ChatDaten.ServerUrl + Constants.GetChatGroupsUrl;

            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;

            var client = new RestClient(url);
            var request = new RestRequest();

            request.AddHeader(Constants.Token, ChatDaten.AuthToken);
            request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

            client.ExecuteAsync(request, response =>
            {
                var groups = JsonConvert.DeserializeObject<ChatGruppenDaten>(response.Content);

                callback?.Invoke(groups);
            });
        }

        public List<Contact> UpdateContacts(ChatGruppenDaten chatDaten)
        {
            try
            {
                _Contacts.Clear();
                
                if(chatDaten?.Response != null)
                {
                    _Contacts.AddRange(GenerateContactsFromServerResponse(chatDaten.Response.Groups.ToArray()));
                }

                return _Contacts;
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
                return null;
            }
        }

        public List<Contact> GenerateContactsFromServerResponse(GroupInput[] pGroupInputs, bool pShouldUpdateLastTimeStamp = false)
        {
            var contacts = new List<Contact>();
            
            foreach(var groupInput in pGroupInputs)
            {
                var formattedTime = new DateTime();

                var latestMessage = groupInput.LastMessage;

                if(latestMessage?.Text != null)
                {
                    var timeStamp = DateTime.Parse(latestMessage.Timestamp.Date);
                    var clientZone = TimeZoneInfo.Local;

                    formattedTime = TimeZoneInfo.ConvertTimeFromUtc(timeStamp, clientZone);
                }

                string userIdManage = null;

                foreach(var user in groupInput.Users)
                {
                    if(user.Oid != ChatDaten.Userid)
                    {
                        if(!user.Is_Employee && !string.IsNullOrEmpty(user.Userid_Manage))
                        {
                            userIdManage = user.Userid_Manage;
                        }
                    }
                }

                var key = $"group-{groupInput.Oid}";
                
                contacts.Add(new Contact(
                    groupInput.Name, 
                    groupInput.LastMessage, 
                    formattedTime, 
                    groupInput.Oid, 
                    userIdManage, 
                    groupInput.OnlyEmployees, 
                    groupInput.Users.Length, 
                    groupInput.CanWrite, 
                    groupInput.AccentColor, 
                    groupInput.Avatar,
                    key, groupInput.Users.ToDictionary(user => user.Oid, user => user.Picture)));

                if(pShouldUpdateLastTimeStamp)
                {
                    if(latestMessage?.Timestamp?.Date != null)
                    {
                        var unixTimeStamp = DateTime.Parse(latestMessage.Timestamp.Date).GetUnixTimeStamp();

                        if(LastTimeStamp < unixTimeStamp)
                        {
                            LastTimeStamp = unixTimeStamp;
                        }
                    }
                }
            }

            return contacts;
        }

        public List<ChatMessage> AddMessagesFromServerResponse(Messages[] pMessages, ChatMessage previousMessage)
        {
            var result = new List<ChatMessage>();

            foreach (var message in pMessages)
            {
                var time                   = DateTime.Parse(message.Timestamp.Date);
                var clientZone             = TimeZoneInfo.Local;
                var formattedTime          = TimeZoneInfo.ConvertTimeFromUtc(time, clientZone);
                var isLoggedInUsersMessage = ChatDaten.Userid != null && message.UserId == ChatDaten.Userid.Value;
                var messageText            = message.Text ?? (string.IsNullOrEmpty(message.File) ? string.Empty : message.Original_Filename);

                if (!string.IsNullOrEmpty(message.File))
                {
                    var message2Add = Constants.ImageFileExtensions.Contains(Path.GetExtension(message.File).ToUpperInvariant()) ? //SmallerImage ist null
                        new ChatMessage(message.GroupId, message.Id, message.User_Name, messageText, formattedTime, isLoggedInUsersMessage, message.FileSize, message.Smaller_Image, message.File, message.Original_Filename, null, null, ChatMessageType.Image, message.UserId) :
                        new ChatMessage(message.GroupId, message.Id, message.User_Name, messageText, formattedTime, isLoggedInUsersMessage, 0, message.File, null, null, message.Smaller_Image, null, ChatMessageType.Document, message.UserId);

                    result.AddIfNotIn(message2Add);
                }
                else
                {
                    var chatMessage = new ChatMessage(message.GroupId, message.Id, message.User_Name, message.Text, formattedTime, isLoggedInUsersMessage, message.FileSize, null, null, null, null, null, ChatMessageType.Message, message.UserId);
                    
                    result.AddIfNotIn(chatMessage);
                }
            }

            return AddSeparators(result);
        }

        private static List<ChatMessage> AddSeparators(List<ChatMessage> chatMessages)
        {
            var messagesWithoutSeparators = chatMessages.Where(message => !message.IsSeparator).OrderBy(message => message.SendTime).ToList();

            var separators = new List<ChatMessage>();

            var previousMessage = messagesWithoutSeparators.OrderBy(message => message.SendTime).FirstOrDefault();
            foreach(var message in messagesWithoutSeparators.OrderBy(message => message.SendTime))
            {
                if(!message.Equals(previousMessage) && previousMessage != null)
                {
                    if(message.SendTime.Date != previousMessage.SendTime.Date)
                    {
                        var separatorMessage = new ChatMessage(0, -1, null, null, message.SendTime.Date, false, 0, null, null, null, null, null, ChatMessageType.Separator, 0);

                        separators.Add(separatorMessage);

                        previousMessage = message;
                    }
                }
            }

            chatMessages.AddRange(separators);

            return chatMessages;
        }

        public void DownloadFileAsync(string uri, string path, Action callback)
        {
            try
            {
                var client = new RestClient(uri);
                var request = new RestRequest();

                request.AddHeader(Constants.Token, ChatDaten.AuthToken);
                request.AddHeader(Constants.CustomerId, ChatDaten.Kundennummer);

                client.ExecuteAsync(request, response =>
                {
                    if(response.StatusCode == HttpStatusCode.OK)
                    {
                        response.RawBytes.SaveAs(path);
                    }
                    else
                    {
                        throw new Exception("Die Datei konnte nicht heruntergeladen werden.");
                    }

                    callback?.Invoke();
                });
            }
            catch (Exception exception)
            {
                ExceptionCallback?.Invoke(exception);
            }
        }
    }

    public class ChatMessageComparer : IComparer
    {
        public int Compare(object x, object y)
        {
            if(x is ChatMessage message1 && y is ChatMessage message2)
            {
                return message1.SendTime.CompareTo(message2.SendTime);
            }

            return 0;
        }
    }
}
