using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using System;
using System.Linq;
using System.Text;
public class RichText : Text, IPointerClickHandler
{
    /// 
    /// 最终显示文本
    /// 
    private string m_OutputText;
    private string m_RichText = string.Empty;
    public Action OnClick;
    #region 对外参数
    [SerializeField]
    private float m_ImgDeltay = 0;
    public float ImgDeltay
    {
        get
        {
            return m_ImgDeltay;
        }
        set
        {
            m_ImgDeltay = value;
            SetVerticesDirty();
        }
    }
    [SerializeField]
    private float m_unlineDeltay = 0;
    public float UnlineDeltay
    {
        get
        {
            return m_unlineDeltay;
        }
        set
        {
            m_unlineDeltay = value;
        }
    }
    [SerializeField]
    private float m_unlineHeight = 1;
    public float UnlineHeight
    {
        get
        {
            return m_unlineHeight;
        }
        set
        {
            m_unlineHeight = value;
        }
    }
    [SerializeField]
    private float m_faceSize = 32;
    public float FaceSize
    {
        get
        {
            return m_faceSize;
        }
        set
        {
            m_faceSize = value;
        }
    }
    [SerializeField]
    private bool m_unline = true;
    public bool Unline
    {
        get { return m_unline; }
        set { m_unline = value; }
    }
    [SerializeField]
    private bool m_HrefClick = true;
    public bool HrefClick
    {
        get { return m_HrefClick; }
        set { m_HrefClick = value; }
    }
    [SerializeField]
    private string m_EnableDisplay;
    public string enableDisplay
    {
        get { return m_EnableDisplay; }
        set { m_EnableDisplay = value; }
    }
    [SerializeField]
    private bool m_Language = false;
    public bool language
    {
        get { return m_Language; }
        set { m_Language = value; }
    }
    [SerializeField]
    private bool m_AutoNewLine = false;
    public bool AutoNewLine
    {
        get
        {
            return m_AutoNewLine;
        }
        set
        {
            m_AutoNewLine = value;
            SetRichTextDirty();
        }
    }
    [SerializeField]
    private bool m_LockImgSize = false;
    public bool LockImgSize
    {
        get
        {
            return m_LockImgSize;
        }
        set
        {
            m_LockImgSize = value;
        }
    }
    [SerializeField]
    private bool m_ModifyImgSize = false;
    public bool ModifyImgSiez
    {
        get { return m_ModifyImgSize; }
        set { m_ModifyImgSize = value; }
    }
    [SerializeField]
    private float m_ModifyImgWidth = 0;
    public float ModifyImgWidth
    {
        get { return m_ModifyImgWidth; }
        set { m_ModifyImgWidth = value; }
    }
    [SerializeField]
    private float m_ModifyImgHeight = 0;
    public float ModifyImgHeight
    {
        get { return m_ModifyImgHeight; }
        set { m_ModifyImgHeight = value; }
    }
    [SerializeField]
    private ColorType m_ColorType = ColorType.Dark;
    public ColorType colorType
    {
        get { return m_ColorType; }
        set { m_ColorType = value; }
    }
    public enum ColorType
    {
        Dark,
        Bright,
    }
    #endregion
    protected override void Awake()
    {
#if UNITY_EDITOR
        if (UnityEditor.PrefabUtility.GetPrefabType(this) == UnityEditor.PrefabType.Prefab)
        {
            return;
        }
#endif 
        unline = transform.GetComponentInChildren();
        if (unline == null)
        {
            GameObject obj = BuiltInLoader.LoadPrefab("TextUnline");
            // GameObject obj = UILoader.LoadPrefab("TextUnline") as GameObject;
            obj = Instantiate(obj);
            obj.transform.SetParent(transform);
            obj.transform.localScale = Vector3.one;
            unline = obj.GetComponent();
            unline.raycastTarget = false;
        }
    }
    protected override void OnEnable()
    {
        base.OnEnable();
#if UNITY_EDITOR
        if (UnityEditor.PrefabUtility.GetPrefabType(this) == UnityEditor.PrefabType.Prefab)
        {
            return;
        }
#endif 
        if (language && !string.IsNullOrEmpty(enableDisplay) && Application.isPlaying/* && ConfigInitiator.done*/)
        {
            text = Language.Get(enableDisplay);
        }
    }
    #region 绘制
    private UIVertex vert = new UIVertex();
    protected override void OnPopulateMesh(VertexHelper toFill)
    {
        if (font == null) return;
        toFill.Clear();
        base.OnPopulateMesh(toFill);
        CalcBounds(toFill);
        #region 修改图片位置
        if (m_ImgList == null) return;
        for (int i = 0; i < m_ImgList.Count; i++)
        {
            int _imgEnd = m_ImgList[i].end;
            RectTransform rt = m_ImgPool[i].rectTransform;
            Vector2 _imgSize = rt.sizeDelta;
            if (_imgEnd < toFill.currentIndexCount)
            {
                try
                {
                    toFill.PopulateUIVertex(ref vert, _imgEnd);
                    rt.localPosition = new Vector2(vert.position.x + _imgSize.x / 2, vert.position.y + _imgSize.y / 2 - m_ImgDeltay);
                    toFill.PopulateUIVertex(ref vert, _imgEnd - 3);
                    Vector3 pos = vert.position;
                    for (int j = _imgEnd, k = _imgEnd - 3; j >= k; j--)
                    {
                        toFill.PopulateUIVertex(ref vert, j);
                        pos.y = Mathf.Min(pos.y, vert.position.y - ImgDeltay);
                        vert.position = pos;
                        toFill.SetUIVertex(vert, j);
                    }
                }
                catch (System.Exception)
                {
                    continue;
                }
            }
        }
        #endregion
    }
    public override void SetVerticesDirty()
    {
        base.SetVerticesDirty();
#if UNITY_EDITOR
        if (UnityEditor.PrefabUtility.GetPrefabType(this) == UnityEditor.PrefabType.Prefab)
        {
            return;
        }
#endif 
        //m_OutputText = GetOutputText(m_RichText);
        GenerateImg();
    }
    #endregion
    #region 解析
    private string GetOutputText(string _text)
    {
        string result = _text;
        result = GetExtenalData(result);
        result = GetTaskInfo(result);
        result = RichTextMgr.Inst.Analysis(result, out m_ImgList, out m_HrefList, this);
        return result;
    }
    #endregion
    #region 图片
    private List m_ImgList;
    private List m_ImgPool = new List();
    private void GenerateImg()
    {
        if (m_ImgList == null) return;
        m_ImgPool.Clear();
        GetComponentsInChildren(true, m_ImgPool);
        for (int i = 0; i < m_ImgList.Count; i++)
        {
            RichTextMgr.ImgInfo imgInfo = m_ImgList[i];
            Image img;
            if (i >= m_ImgPool.Count)
            {
                img = CreateImg();
                m_ImgPool.Add(img);
            }
            else
            {
                img = m_ImgPool[i];
            }
            img.SetActive(true);
            img.raycastTarget = HrefClick;
            img.sprite = imgInfo.sprite;
            Vector2 _imgSize = new Vector2(imgInfo.width, imgInfo.height);
            img.rectTransform.sizeDelta = _imgSize;
            UIFrame frame = img.GetComponent();
            if (imgInfo.IsFace)
            {
                if (frame == null) frame = img.gameObject.AddComponent();
                img.raycastTarget = false;
                frame.ResetFrame(imgInfo.spriteName);
                frame.enabled = true;
            }
            else
            {
                if (frame != null) frame.enabled = false;
            }
        }
        for (int i = m_ImgPool.Count - 1; i >= m_ImgList.Count; i--)
        {
            m_ImgPool[i].SetActive(false);
        }
    }
    private Image CreateImg()
    {
        DefaultControls.Resources res = new DefaultControls.Resources();
        GameObject go = DefaultControls.CreateImage(res);
        go.layer = gameObject.layer;
        RectTransform rt = go.transform as RectTransform;
        if (rt != null)
        {
            rt.SetParent(rectTransform);
            rt.localPosition = Vector3.zero;
            rt.localRotation = Quaternion.identity;
            rt.localScale = Vector3.one;
        }
        Image img = go.GetComponent();
        return img;
    }
    #endregion
    #region 下划线||超链接
    [SerializeField]
    private TextUnline unline;
    private List m_HrefList;
    private Dictionary m_UnlineBottomDict = new Dictionary();
    private float GetUnlineHeight(int _line)
    {
        foreach (var _key in m_UnlineBottomDict.Keys)
        {
            if (_line <= _key)
            {
                return m_UnlineBottomDict[_key];
            }
        }
        return m_UnlineBottomDict.Values.Last();
    }
    public string GetHrefMessage(string _key)
    {
        if (m_HrefList != null)
        {
            for (int i = 0; i < m_HrefList.Count; i++)
            {
                if (m_HrefList[i].mSplits.ContainsKey(_key))
                {
                    return m_HrefList[i].mSplits[_key];
                }
            }
        }
        return string.Empty;
    }
    private void CalcBounds(VertexHelper toFill)
    {
        if (unline != null) unline.ClearVert();
        if (m_HrefList == null) return;
        float minBottom = 0;
        if (!Unline)
        {
            return;
        }
        m_UnlineBottomDict.Clear();
        int _line = 0;
        bool _note = false;
        foreach (RichTextMgr.HrefInfo hrefInfo in m_HrefList)
        {
            CalcUnline(toFill, hrefInfo);
            if (!hrefInfo.unline)
            {
                continue;
            }
            hrefInfo.lines.Clear();
            for (int i = 0; i < hrefInfo.boxs.Count; i++)
            {
                Vector3 start = hrefInfo.boxs[i].position;
                if (minBottom == 0 && !_note)
                {
                    minBottom = start.y;
                    _note = true;
                }
                if (Math.Abs(minBottom - start.y) >= fontSize / 2)
                {
                    m_UnlineBottomDict.Add(_line, minBottom);
                    minBottom = start.y;
                    _line++;
                }
                else
                {
                    minBottom = Mathf.Min(start.y, minBottom);
                }
                hrefInfo.lines.Add(_line);
            }
        }
        m_UnlineBottomDict.Add(_line, minBottom);
        foreach (RichTextMgr.HrefInfo hrefInfo in m_HrefList)
        {
            if (!hrefInfo.unline)
            {
                continue;
            }
            for (int i = 0; i < hrefInfo.boxs.Count; i++)
            {
                Vector3 start = hrefInfo.boxs[i].position;
                var _unlineline = i < hrefInfo.lines.Count ? hrefInfo.lines[i] : 0;
                start.y = GetUnlineHeight(_unlineline);
                Vector3 end = start;
                end.x += hrefInfo.boxs[i].width;
                unline.SetUIVertex(start, end, -UnlineDeltay, m_unlineHeight, hrefInfo.unlineColor);
            }
        }
    }
    private void CalcUnline(VertexHelper toFill, RichTextMgr.HrefInfo hrefInfo)
    {
        hrefInfo.boxs.Clear();
        if (hrefInfo.start >= toFill.currentIndexCount) return;
        try
        {
            toFill.PopulateUIVertex(ref vert, hrefInfo.start);
        }
        catch (System.Exception)
        {
            return;
        }
        Vector3 pos = vert.position;
        var realStart = hrefInfo.start;
        ///-----为了过滤颜色导致多次添加包围盒
        while (realStart <= hrefInfo.end)
        {
            try
            {
                toFill.PopulateUIVertex(ref vert, realStart);
                if (pos != vert.position)
                {
                    if (realStart <= hrefInfo.start + 1)
                    {
                        realStart = hrefInfo.start;
                    }
                    else
                    {
                        pos = vert.position;
                    }
                    break;
                }
            }
            catch (Exception)
            {
                return;
            }
            realStart++;
        }
        Bounds bounds = new Bounds(pos, Vector3.zero);
        int _Cnt = 0;
        for (int i = realStart, k = hrefInfo.end; i <= k; i++)
        {
            if (i >= toFill.currentIndexCount) break;
            try
            {
                toFill.PopulateUIVertex(ref vert, i);
            }
            catch (System.Exception)
            {
                break;
            }
            pos = vert.position;
            if (pos.x - 0.1 <= bounds.min.x && _Cnt > 3)
            {
                hrefInfo.boxs.Add(new Rect(bounds.min, bounds.size));
                bounds = new Bounds(pos, Vector3.zero);
                _Cnt = 0;
            }
            bounds.Encapsulate(pos);
            _Cnt++;
        }
        hrefInfo.boxs.Add(new Rect(bounds.min, bounds.size));
    }
    #endregion
    #region 自适应
    public override float preferredWidth
    {
        get
        {
            if (font == null && Application.isPlaying)
            {
                font = FontUtility.preferred;
            }
            var settings = GetGenerationSettings(Vector2.zero);
            return cachedTextGeneratorForLayout.GetPreferredWidth(m_OutputText, settings) / pixelsPerUnit;
        }
    }
    public override float preferredHeight
    {
        get
        {
            if (font == null && Application.isPlaying)
            {
                font = FontUtility.preferred;
            }
            var settings = GetGenerationSettings(new Vector2(rectTransform.rect.size.x, 0.0f));
            float _height = cachedTextGeneratorForLayout.GetPreferredHeight(m_OutputText, settings) / pixelsPerUnit;
            return _height;
        }
    }
    #endregion
    #region 外部数据
    private static readonly string FORMAT_PATTERN = @"\%s([0-9]+)";
    private ArrayList extenalData = new ArrayList();
    public void SetExtenalData(params object[] msg)
    {
        extenalData.Clear();
        if (msg != null && msg.Length > 0)
        {
            extenalData.AddRange(msg);
        }
    }
    public void SetExtenalData(ICollection collection)
    {
        extenalData.Clear();
        if (collection != null && collection.Count > 0)
        {
            extenalData.AddRange(collection);
            collection = null;
        }
    }
    private string GetExtenalData(string val)
    {
        textBuilder.Length = 0;
        int index = 0;
        if (Regex.IsMatch(val, FORMAT_PATTERN))
        {
            foreach (Match match in Regex.Matches(val, FORMAT_PATTERN))
            {
                textBuilder.Append(val.Substring(index, match.Index - index));
                int infoIndex = 0;
                int.TryParse(match.Groups[1].Value, out infoIndex);
                if (extenalData != null && infoIndex < extenalData.Count)
                {
                    textBuilder.Append(extenalData[infoIndex]);
                }
                else
                {
                    textBuilder.Append(0);
                }
                index = match.Index + match.Length;
            }
            textBuilder.Append(val.Substring(index, val.Length - index));
            return textBuilder.ToString();
        }
        else
        {
            return val;
        }
    }
    #region 任务数据
    private Dictionary extenalDataDic = null;
    private const string Info_Pattern = "{([a-zA-Z0-9_]+)}";
    public void SetReplaceInfo(Dictionary _infoDic)
    {
        extenalDataDic = _infoDic;
        SetRichTextDirty();
    }
    private string GetTaskInfo(string val)
    {
        textBuilder.Length = 0;
        int index = 0;
        if (Regex.IsMatch(val, Info_Pattern))
        {
            foreach (Match match in Regex.Matches(val, Info_Pattern))
            {
                textBuilder.Append(val.Substring(index, match.Index - index));
                if (extenalDataDic != null && extenalDataDic.ContainsKey(match.Groups[1].Value))
                {
                    textBuilder.Append(extenalDataDic[match.Groups[1].Value]);
                }
                else
                {
                    textBuilder.Append(0);
                }
                index = match.Index + match.Length;
            }
            textBuilder.Append(val.Substring(index, val.Length - index));
            return textBuilder.ToString();
        }
        else
        {
            return val;
        }
    }
    #endregion
    #endregion
    #region 执行事件
    public void OnPointerClick(PointerEventData eventData)
    {
        OnClick?.Invoke();
        if (HrefClick)
        {
            Vector2 lp;
            RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform,
                eventData.position, eventData.pressEventCamera, out lp);
            if (m_HrefList != null)
            {
                foreach (var hrefInfo in m_HrefList)
                {
                    List boxs = hrefInfo.boxs;
                    for (int i = 0; i < boxs.Count; i++)
                    {
                        if (boxs[i].Contains(lp))
                        {
                            hrefInfo.Execute();
                            return;
                        }
                    }
                }
            }
        }
    }
    public void OnImgClick()
    {
    }
    public void ExcuteHref(int eventIndex = 0, int hrefIndex = 0)
    {
        if (m_HrefList == null || m_HrefList.Count <= 0
            || hrefIndex < 0) return;
        if (hrefIndex < m_HrefList.Count)
        {
            m_HrefList[hrefIndex].Execute(eventIndex);
        }
    }
    #endregion
    #region 自适应2
    /// 
    /// 牺牲了主动换行
    /// 
    private static StringBuilder textBuilder = new StringBuilder();
    private Dictionary matchDics = new Dictionary();
    private bool IsModifySize(int _index,out int _size)
    {
        _size = 0;
        int _end = 0;
        int _before = -1;
        foreach (var _key in matchDics.Keys)
        {
            if (_index < _key)
            {
                var _match = matchDics[_key];
                if (WordAnalysis.Size_Start_Regex.IsMatch(_match.Value))
                {
                    break;
                }
                else if (WordAnalysis.Size_End_Regex.IsMatch(_match.Value))
                {
                    _end = _key;
                    break;
                }
            }
        }
        if (_end != 0)
        {
            foreach (var _key in matchDics.Keys)
            {
                if (_key < _end)
                {
                    var _match = matchDics[_key];
                    if (WordAnalysis.Size_Start_Regex.IsMatch(_match.Value))
                    {
                        _before = _key;
                    }
                }
                else
                {
                    break;
                }
            }
        }
        if (_before != -1)
        {
            _size = int.Parse(matchDics[_before].Groups[1].Value);
            return true;
        }
        return false;
    }
    public void SetFitterSize()
    {
        string fitterText = m_OutputText;
        fitterText = fitterText.Replace("\n", "");
        float width = 0;
        textBuilder.Length = 0;
        if (null == font && Application.isPlaying)
        {
            font = FontUtility.preferred;
        }
        var settings = GetGenerationSettings(Vector2.zero);
        float cache = 0;
        string part = string.Empty;
        float ratio = GetResolutionRatio();
        matchDics.Clear();
        foreach (Match match in ImgAnalysis.Unity_Img_Regex.Matches(fitterText))
        {
            if (!matchDics.ContainsKey(match.Index))
            {
                matchDics.Add(match.Index, match);
            }
        }
        foreach (Match match in WordAnalysis.Color_Start_Regex.Matches(fitterText))
        {
            if (!matchDics.ContainsKey(match.Index))
            {
                matchDics.Add(match.Index, match);
            }
        }
        foreach (Match match in WordAnalysis.Color_End_Regex.Matches(fitterText))
        {
            if (!matchDics.ContainsKey(match.Index))
            {
                matchDics.Add(match.Index, match);
            }
        }
        bool _modifySize = false;
        foreach (Match match in WordAnalysis.Size_Start_Regex.Matches(fitterText))
        {
            if (!matchDics.ContainsKey(match.Index))
            {
                _modifySize = true;
                matchDics.Add(match.Index, match);
            }
        }
        foreach (Match match in WordAnalysis.Size_End_Regex.Matches(fitterText))
        {
            if (!matchDics.ContainsKey(match.Index))
            {
                matchDics.Add(match.Index, match);
            }
        }
        for (int i = 0; i < fitterText.Length; i++)
        {
            if (matchDics.ContainsKey(i))
            {
                Match match = matchDics[i];
                if (ImgAnalysis.Unity_Img_Regex.IsMatch(match.Value))
                {
                    width += match.Length;
                }
                if (WordAnalysis.Color_Start_Regex.IsMatch(match.Value))
                {
                    textBuilder.Append(match.Value);
                }
                else if (WordAnalysis.Color_End_Regex.IsMatch(match.Value))
                {
                    textBuilder.Append(match.Value);
                }
                else if (WordAnalysis.Size_Start_Regex.IsMatch(match.Value))
                {
                    textBuilder.Append(match.Value);
                }
                else if (WordAnalysis.Size_End_Regex.IsMatch(match.Value))
                {
                    textBuilder.Append(match.Value);
                }
                else
                {
                    cache = cachedTextGeneratorForLayout.GetPreferredWidth(match.Value, settings) * ratio;
                    if (width + cache > (rectTransform.rect.width - 5))
                    {
                        CacluHrefAndImgIndex(Mathf.Max(0, i - 1));
                        textBuilder.Append("\n");
                        width = cache;
                    }
                    else
                    {
                        width += cache;
                    }
                    textBuilder.Append(match.Value);
                }
                i += (match.Length - 1);
            }
            else
            {
                var _size = 0;
                var _cacheFontSize = fontSize;
                if (_modifySize && IsModifySize(i, out _size))
                {
                    fontSize = _size;
                    settings = GetGenerationSettings(Vector2.zero);
                    cache = cachedTextGeneratorForLayout.GetPreferredWidth(fitterText[i].ToString(), settings) * ratio;
                    fontSize = _cacheFontSize;
                    settings = GetGenerationSettings(Vector2.zero);
                }
                else
                {
                    cache = cachedTextGeneratorForLayout.GetPreferredWidth(fitterText[i].ToString(), settings) * ratio;
                }
                if (width + cache > (rectTransform.rect.width - 5))
                {
                    CacluHrefAndImgIndex(Mathf.Max(0, i - 1));
                    textBuilder.Append("\n");
                    width = cache;
                }
                else
                {
                    width += cache;
                }
                textBuilder.Append(fitterText[i]);
            }
        }
        CacluHrefAndImgIndex();
        m_OutputText = textBuilder.ToString();
    }
    private void CacluHrefAndImgIndex(int index)
    {
        for (int i = 0; i < m_ImgList.Count; i++)
        {
            if (index * 4 < m_ImgList[i].end)
            {
                m_ImgList[i].cacheCnt += 1;
            }
        }
        for (int m = 0; m < m_HrefList.Count; m++)
        {
            RichTextMgr.HrefInfo hrefInfo = m_HrefList[m];
            if (index * 4 < hrefInfo.end)
            {
                hrefInfo.end_cache_cnt += 1;
            }
            if (index * 4 < hrefInfo.start)
            {
                hrefInfo.start_cache_cnt += 1;
            }
        }
    }
    private void CacluHrefAndImgIndex()
    {
        for (int i = 0; i < m_ImgList.Count; i++)
        {
            m_ImgList[i].end += m_ImgList[i].cacheCnt * 4;
        }
        for (int m = 0; m < m_HrefList.Count; m++)
        {
            RichTextMgr.HrefInfo hrefInfo = m_HrefList[m];
            hrefInfo.start += hrefInfo.start_cache_cnt * 4;
            hrefInfo.end += hrefInfo.end_cache_cnt * 4;
        }
    }
    private float GetResolutionRatio()
    {
        return 1 / pixelsPerUnit;
    }
    public override string text
    {
        get
        {
            return m_Text;
        }
        set
        {
            if (string.IsNullOrEmpty(value))
            {
                value = string.Empty;
            }
            m_RichText = value;
            SetRichTextDirty();
        }
    }
#if UNITY_EDITOR
    protected override void OnValidate()
    {
        text = m_Text;
    }
#endif
    private void SetRichTextDirty()
    {
        m_RichText = UIHelper.ReplaceNewLine(m_RichText);
        m_OutputText = GetOutputText(m_RichText);
        if (AutoNewLine)
        {
            SetFitterSize();
        }
        m_Text = m_OutputText;
        SetVerticesDirty();
        SetLayoutDirty();
    }
    #endregion
}