using Oraycn.ChatRendering;
using System;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Markup;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Xml;

namespace OVCS.ClientWpf.Controls.ChatBox
{
    /// <summary>
    /// ChatInputBox.xaml 的交互逻辑
    /// </summary>
    public partial class ChatInputBox : UserControl
    {
        private bool isPaste = false;
        private Dictionary<int ,ImageSource> emojiDic = new Dictionary<int, ImageSource>();

        public ChatInputBox()
        {
            InitializeComponent();
        }


        #region 属性
        /// <summary>
        /// 富文本编辑器
        /// </summary>
        public RichTextBox RichTextBox => this.inputbox;

        /// <summary>
        /// 发送文件事件 ，string: filePath
        /// </summary>
        public event Action<string> SendFileEvent;

        /// <summary>
        /// 发送图片事件
        /// </summary>
        public event Action<Bitmap> SendImageEvent;

        /// <summary>
        /// 发送文本事件
        /// </summary>
        public event Action<string> SendTextEvent;

        #endregion

        #region 对外方法
        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="emojiDic">表情字典。 int: 表情的索引，ImageSource：索引对应的图像源·</param>
        public void Initialize(Dictionary<int, ImageSource> emojiDic)
        {
            this.emojiDic = emojiDic;
        }

        /// <summary>
        /// 当前光标上插入表情
        /// </summary>
        /// <param name="emojiIndex">表情对于的索引</param>
        public void InsertEmoji(int emojiIndex)
        {
            Span span = this.CreateEmojiSpan(emojiIndex);
            this.Insert4Index(span);
            inputbox.Focus();
        }

        //创建Emoji的Span插入到输入框
        private Span CreateEmojiSpan(int emojiIndex)
        {
            System.Windows.Controls.Image img = new System.Windows.Controls.Image();
            img.Width = 18;
            img.Height = 18;
            img.IsEnabled = true;
            img.Source = this.emojiDic[emojiIndex];
            InlineUIContainer inline = new InlineUIContainer(img);
            Span span = new Span(inline);
            span.Tag = emojiIndex;
            return span;
        }

        /// <summary>
        /// 获取输入框内容
        /// </summary>
        /// <returns></returns>
        public string GetInputBoxContent()
        {
            StringBuilder sb = new StringBuilder("");
            XmlDocument xml = new XmlDocument();
            xml.InnerXml = XamlWriter.Save(this.inputbox.Document);
            XmlNode xmlNode = xml.FirstChild;
            XmlNodeList xmlNodeList = xmlNode.ChildNodes;
            bool firstLine = true;
            foreach (XmlNode node in xmlNodeList)
            {
                if (node.Name == "Paragraph")
                {
                    if (!firstLine) { sb.Append("\n"); }
                    firstLine = false;
                    XmlNodeList memberNodeList = node.ChildNodes;
                    foreach (XmlNode item in memberNodeList)
                    {
                        XmlNode memberNode = item;
                        if (memberNode.Name == "Span")
                        {
                            memberNode = memberNode.FirstChild;
                        }
                        if (memberNode.Name == "Image")
                        {
                            string s = memberNode.OuterXml;

                            System.Text.RegularExpressions.Regex r = new System.Text.RegularExpressions.Regex(@"\\.+?\\(.+)\.png");
                            string s1 = r.Match(s).Groups[1].Value;
                            string[] sArr = s1.Split('\\');
                            int index = -1;
                            int.TryParse(sArr[sArr.Length - 1], out index);
                            if (index > -1)
                            {
                                string realIndex = (index - 1).ToString();
                                string imgIndex = realIndex.ToString().PadLeft(3, '0'); // results in 009
                                sb.Append($"[{imgIndex}]");
                            }
                            else
                            {
                                sb.Append(" ");
                            }
                        }
                        else if (memberNode.Name == "Span.Tag")
                        {
                            string imgIndex = memberNode.InnerText.ToString().PadLeft(3, '0'); // results in 009
                            sb.Append($"[{imgIndex}]");
                        }
                        else
                        {
                            sb.Append(memberNode.InnerText);
                        }
                    }
                }
            }
            return sb.ToString();
        }

        /// <summary>
        /// 设置禁言
        /// </summary>
        /// <param name="tips"></param>
        public void SetBan(string tips)
        {
            this.inputbox.IsEnabled = false;
            this.bannedLabel.Visibility = Visibility.Visible;
            this.groupBan.Text = tips ?? "禁言中...";
        }

        /// <summary>
        /// 移除禁言
        /// </summary>
        public void RemoveBan()
        {
            this.inputbox.IsEnabled = true;
            this.bannedLabel.Visibility = Visibility.Collapsed;
        }

        /// <summary>
        /// 清空输入框
        /// </summary>
        public void Clear()
        {
            FlowDocument enter = inputbox.Document;
            enter.Blocks.Clear();
        }

        #endregion

        private void Inputbox_Drop(object sender, DragEventArgs e)
        {
            Debug.WriteLine("拖动");
        }

        private void RichTextBox_DragOver(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                e.Effects = DragDropEffects.All;
            }
            else
            {
                e.Effects = DragDropEffects.None;
            }
            e.Handled = false;
        }

        private void RichTextBox_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                string[] docPath = (string[])e.Data.GetData(DataFormats.FileDrop);
                var dataFormat = DataFormats.Rtf;
                if (e.KeyStates == DragDropKeyStates.ShiftKey)
                {
                    dataFormat = DataFormats.Text;
                }

                System.Windows.Documents.TextRange range;
                System.IO.FileStream fStream;
            }
        }

        /// <summary>
        /// 键盘输入
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void inputbox_PreviewKeyDown(object sender, KeyEventArgs e)
        {
            try
            {
                if (e.Key == Key.Left || e.Key == Key.Right || e.Key == Key.Back || e.Key == Key.Up)
                {

                }
                if (e.Key == Key.Enter && Keyboard.Modifiers != ModifierKeys.Control)
                {
                    SendText();
                    e.Handled = true;
                    return;
                }
                if (e.Key == Key.Enter)
                {
                    BlockCollection blocks = inputbox.Document.Blocks;
                    Paragraph paragraph = inputbox.Selection.Start.Paragraph;
                    Paragraph paragraph1 = new Paragraph();
                    blocks.InsertAfter(paragraph, paragraph1);
                    inputbox.CaretPosition = paragraph1.ContentStart;
                    return;
                }
                TextRange textRange = new TextRange(inputbox.Document.ContentStart, inputbox.Document.ContentEnd);
                string text = textRange.Text;

                if (isPaste || (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.V))
                {
                    isPaste = false;
                    TextRange txt = new TextRange(inputbox.Selection.Start, inputbox.Selection.End);
                    txt.Text = "";
                    string content = this.GetInputBoxContent();
                    IDataObject iData = Clipboard.GetDataObject();
                    if (iData.GetDataPresent(DataFormats.Text))
                    {
                        var path = (String)iData.GetData(DataFormats.Text);
      
                        if (File.Exists(path))
                        {
                            SendFile(path);
                        }
                        else
                        {
                            string copy = Clipboard.GetText();
                            if (!IsExistEmoji(copy))
                            {
                                return;
                            }
                            PasteToInputBox(copy);
                        }
                    }
                    else if (iData.GetDataPresent(DataFormats.MetafilePicture))
                    {
                        BitmapSource bitmapSource = Clipboard.GetImage();
                        if (bitmapSource != null)
                        {
                            Bitmap bitmap = this.ImageSource2Bitmap2Rgb(bitmapSource);
                            SendImage(bitmap);
                        }
                    }
                    else if (iData.GetDataPresent(DataFormats.FileDrop))
                    {
                        StringCollection filePaths = Clipboard.GetFileDropList();
                        if (filePaths.Count == 0) { return; }
                        if (System.IO.File.Exists(filePaths[0]))
                        {
                            SendFile(filePaths[0]);
                        }
                    }
                    else if (iData.GetDataPresent(DataFormats.Bitmap) && Clipboard.ContainsImage())
                    {
                        BitmapSource bitmapSource = Clipboard.GetImage();
                        Bitmap bitmap1 = this.ImageSource2Bitmap2Rgb(bitmapSource);
                        if (bitmapSource != null)
                        {
                            SendImage(bitmap1);
                        }
                    }
                    if (e.RoutedEvent != null)
                    {
                        e.Handled = true;
                    }
                }
                if (Keyboard.Modifiers == ModifierKeys.Control && e.Key == Key.C)
                {
                    CopyText2Clipboard();
                    e.Handled = true;
                }
            }
            catch (Exception ee)
            {
                MessageBox.Show(ee.Message);
                //throw ee;
            }
        }

        /// <summary>
        /// 判断是否存在表情
        /// </summary>
        /// <param name="richText"></param>
        /// <returns></returns>
        private bool IsExistEmoji(string richText)
        {
            if (richText.Contains('[') && richText.Contains(']'))
            {
                Dictionary<uint, uint> emotionDic_temp = new Dictionary<uint, uint>();
                for (int i = richText.Length - 1; i >= 0; i--)
                {
                    if (richText[i] == '[' && i + 4 < richText.Length)
                    {
                        if (richText[i + 4] == ']')
                        {
                            int emotionIndex = -1;
                            int.TryParse(richText.Substring(i + 1, 3), out emotionIndex);
                            if (emotionIndex > -1 && emotionIndex < this.emojiDic.Count)//中间是表情
                            {
                                return true;
                            }
                        }
                    }
                }
            }
            return false;
        }

        /// <summary>
        /// 复制文本
        /// </summary>
        private void CopyText2Clipboard()
        {
            DependencyObject startDepend = inputbox.Selection.Start.Parent;
            DependencyObject endDepend = inputbox.Selection.End.Parent;
            Paragraph paragraph = inputbox.Selection.Start.Paragraph;
            if (paragraph == null)
            {
                return;
            }
            string start = XamlWriter.Save(startDepend);
            string end = XamlWriter.Save(endDepend);
            string parent = XamlWriter.Save(paragraph);
            InlineCollection inlines = paragraph.Inlines;
            bool isStart = false;
            bool inputBoxisExistEmoji = false;
            foreach (Object obj in inlines)
            {
                Span span = obj as Span;
                if (span != null)
                {
                    inputBoxisExistEmoji = true;
                    break;
                }
            }
            if (!inputBoxisExistEmoji)
            {
                inputbox.Copy();
                return;
            }
            string copyText = string.Empty;
            foreach (Object obj in inlines)
            {
                Span span = obj as Span;
                Run run = obj as Run;
                if (span != null)//表情
                {
                    if (startDepend.Equals(span))
                    {
                        isStart = true;
                    }
                    if (isStart)
                    {
                        if (string.IsNullOrEmpty(span.Tag.ToString()))
                        {
                            foreach (Object test4Span in inlines)
                            {
                                TextBlock textBlock = (TextBlock)test4Span;
                                copyText += textBlock.Text;
                            }
                        }
                        else
                        {
                            int imgRealIndex = (int)(span.Tag);
                            string imgIndex = "[" + imgRealIndex.ToString().PadLeft(3, '0') + "]";
                            copyText += imgIndex;
                        }
                        if (startDepend.Equals(endDepend) || endDepend.Equals(span))
                        {
                            break;
                        }
                    }
                }
                if (run != null)//文本
                {
                    if (startDepend.Equals(run))
                    {
                        isStart = true;
                    }
                    if (isStart)
                    {
                        copyText += run.Text;
                        if (startDepend.Equals(endDepend) || endDepend.Equals(span))
                        {
                            break;
                        }
                    }
                }
            }
            if (!string.IsNullOrEmpty(copyText))
            {
                Clipboard.SetText(copyText);
            }
        }

        /// <summary>
        /// 粘贴到当前输入框的光标处
        /// </summary>
        /// <param name="str"></param>
        private void PasteToInputBox(string str)
        {
            Dictionary<uint, uint> emotions = null;
            str = ChatRenderFactory.ParseEmotionRichText(str, out emotions);
            List<uint> list = emotions.Keys.ToList();
            char[] vs = str.ToArray();
            string tmp = string.Empty;
            for (int i = 0; i < vs.Length; i++)
            {
                bool IsEmotion = false;
                if (list.Count > 0)
                {
                    IsEmotion = list[0] == i;
                }
                if (IsEmotion)
                {
                    if (!string.IsNullOrEmpty(tmp))
                    {
                        this.Insert4Index(null, new Run(tmp));
                        tmp = string.Empty;
                    }    
                    Span span = this.CreateEmojiSpan((int)emotions[(uint)i]);
                    this.Insert4Index(span);
                    list.Remove((uint)i);
                }
                else
                {
                    string charStr = vs[i].ToString();
                    if (charStr == "\n")
                    {
                        if (!string.IsNullOrEmpty(tmp))
                        {
                            this.Insert4Index(null, new Run(tmp));
                            tmp = string.Empty;
                        }
                        Run run = new Run(charStr);
                        this.Insert4Index(null, run);
                        continue;
                    }
                    tmp += charStr;
                }
            }
            if (!string.IsNullOrEmpty(tmp))
            {
                this.Insert4Index(null, new Run(tmp));
                tmp = string.Empty;
            }
        }

        /// <summary>
        /// 插入Span到当前光标
        /// </summary>
        /// <param name="span"></param>
        /// <param name="run"></param>
        private void Insert4Index(Span span, Run run = null)
        {
            TextPointer start = inputbox.Selection.Start;
            TextPointer end = inputbox.Selection.End;
            List<Inline> behinds = new List<Inline>();
            bool isAddBehind = false;
            if (end.Paragraph != null || start.Paragraph != null)
            {
                Paragraph paragraph1;
                if (end.Paragraph != null)
                {
                    paragraph1 = end.Paragraph;
                }
                else
                {
                    paragraph1 = start.Paragraph;
                }
                foreach (Inline obj in paragraph1.Inlines)
                {
                    if (isAddBehind)
                    {
                        behinds.Add(obj);
                    }
                    if (obj.Equals(start.Parent))
                    {
                        isAddBehind = true;
                    }
                }
                foreach (Inline line in behinds)
                {
                    start.Paragraph.Inlines.Remove(line);
                }
                if (run == null)
                {
                    start.Paragraph.Inlines.Add(span);
                    inputbox.CaretPosition = span.ElementEnd;
                }
                else
                {
                    start.Paragraph.Inlines.Add(run);
                    inputbox.CaretPosition = run.ElementEnd;
                }
                start.Paragraph.Inlines.AddRange(behinds);
                return;
            }
            Paragraph paragraph = new Paragraph();
            inputbox.Document.Blocks.Add(paragraph);
            if (run == null)
            {
                paragraph.Inlines.Add(span);
            }
            else
            {
                paragraph.Inlines.Add(run);
            }
            inputbox.CaretPosition = inputbox.Document.ContentEnd;
        }

        #region 发送消息事件

        private void SendText()
        {
            this.SendTextEvent?.Invoke(this.GetInputBoxContent());
        }

        private void SendFile(string path)
        {
            this.SendFileEvent?.Invoke(path);
        }

        private void SendImage(Bitmap bitmap)
        {
            this.SendImageEvent?.Invoke(bitmap);
        } 
        #endregion

        #region Convert
        private System.Drawing.Bitmap ImageSource2Bitmap2Rgb(ImageSource imageSource)
        {
            BitmapSource m = (BitmapSource)imageSource;

            System.Drawing.Bitmap bmp = new System.Drawing.Bitmap(m.PixelWidth, m.PixelHeight, System.Drawing.Imaging.PixelFormat.Format32bppRgb); // 坑点：选Format32bppRgb将不带透明度

            System.Drawing.Imaging.BitmapData data = bmp.LockBits(
            new System.Drawing.Rectangle(System.Drawing.Point.Empty, bmp.Size), System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppPArgb);

            m.CopyPixels(Int32Rect.Empty, data.Scan0, data.Height * data.Stride, data.Stride);
            bmp.UnlockBits(data);

            return bmp;
        }
        #endregion

        #region 复制粘贴
        private void CopyMenuItem_Click(object sender, RoutedEventArgs e)
        {
            CopyText2Clipboard();
        }

        private void PasteMenuItem_Click(object sender, RoutedEventArgs e)
        {
            this.isPaste = true;
            KeyEventArgs keyEventArgs = new KeyEventArgs(Keyboard.PrimaryDevice, Keyboard.PrimaryDevice.ActiveSource, 0, Key.V);
            this.inputbox_PreviewKeyDown(sender, keyEventArgs);
        } 
        #endregion

    }
}
