namespace CounsellorBL.BLStructure.SYS
{
    using CounsellorBL.GROUP.Helper;
    using CounsellorBL.Helper;   
    using MonumentDefine;
    using Newtonsoft.Json;
    using Newtonsoft.Json.Linq;
    using OT.COM.ArsenalDB;
    using OT.COM.LogisticsUtil;
    using OT.COM.SignalerMessage;
    using SoldierData.EnterprizeV4;
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Text.RegularExpressions;
    using static CounsellorBL.GROUP.Helper.FbHelper;

    public class CommentManageService : SingleDataTableTemplate<tb_grp_comment>
    {
        private class CommentViewModel
        {
            public string uid { get; set; }
            public string article_uid { get; set; }
            public string origin_comment { get; set; }
            public string comment { get; set; }
            public DateTime comment_time { get; set; }
            public string group_user_id { get; set; }
            public int status { get; set; }
            public string fb_name { get; set; }
            public string fb_pic { get; set; }
            public string fb_comment_id { get; set; }
            public string group_id { get; set; }
            public string user_name { get; set; }
            public string user_picture { get; set; }
            public string member_uid { get; set; }
            public int status_flag { get; set; }
            public string parent_comment_id { get; set; }
            public string default_branch { get; set; }
        }

        private class GroupViewModel2
        {
            public string fb_article_id { get; set; }
            public string user_token { get; set; }
            public string client_secret { get; set; }
            public string app_id { get; set; }
        }

        public CommentManageService()
        {
            EditMustConditionKeys.Add(tb_grp_comment.CN_ARTICLE_UID);
            dgReadCommandGenerator = readCommandGenerator;
            dgDeleteCommandGenerator = deleteCommandGenerator;
        }

        public new CResponseMessage Read(CRequestMessage i_crmInput) => base.Read(i_crmInput);

        protected string readCommandGenerator(CRequestMessage i_crmInput, JArray i_jaData, tb_sys_session i_sSessionUser, out Command o_c,
           [System.Runtime.CompilerServices.CallerLineNumber] int i_nCodeLine = 0,
           [System.Runtime.CompilerServices.CallerMemberName] string i_sMemberName = "",
           [System.Runtime.CompilerServices.CallerFilePath] string i_sSourcePath = "")
        {
            string sMsg;
            Command cRes = null;
            try
            {
                do
                {
                    // 取得condition
                    Dictionary<string, string> dicCondition = GetQueryMasterFirstQJEDicwherecols(i_crmInput);
                    var lsBranch = ProjectHelper.GetUserGroup(i_crmInput);
                    /**開始組指令**/
                    QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
                    QueryJsonElement qjeArticle = lBlocks.GetInst();
                    qjeArticle.table = tb_grp_article.TABLENAME;
                    qjeArticle.displaycols = new List<string>()
                    {
                        tb_grp_article.CN_UID,
                        tb_grp_article.CN_NAME,
                        tb_grp_article.CN_GROUP_UID,
                        tb_grp_article.CN_MESSAGE,
                        tb_grp_article.CN_FB_ARTICLE_ID,
                        tb_grp_article.CN_STATUS_FLAG,
                        tb_grp_article.CN_RELEASE_DATE,
                        tb_grp_article.CN_REMARK,
                        tb_grp_article.CN_CLOSE_DATE,
                        tb_grp_article.CN_POST_DATE
                    };
                    List<WhereNode> wnQuery = new List<WhereNode>();
                    wnQuery.Add(new WhereNode(tb_grp_article.CN_STATUS_FLAG, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), BLWording.STATUS_FLAG_ON));
                    wnQuery.Add(new WhereNode(tb_grp_article.CN_STATUS_COMMENT, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), BLWording.STATUS_FLAG_ON));
                    wnQuery.Add(new WhereNode(tb_grp_article.CN_FB_ARTICLE_ID, WhereNode.EColumnOperation.EOT_ISNOTNULL, typeof(tb_grp_article)));

                    // 搜尋社團
                    if (dicCondition.ContainsKey(tb_grp_article.CN_GROUP_UID))
                    {
                        wnQuery.Add(new WhereNode(tb_grp_article.CN_GROUP_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), dicCondition[tb_grp_article.CN_GROUP_UID]));
                    }
                    if (dicCondition.ContainsKey(tb_grp_article.CN_CLOSE_DATE))
                    {
                        if (dicCondition[tb_grp_article.CN_CLOSE_DATE] == "1")
                        {
                            wnQuery.Add(new WhereNode(tb_grp_article.CN_CLOSE_DATE, WhereNode.EColumnOperation.EOT_GTEQ, typeof(tb_grp_article), DateTime.Today));
                            wnQuery.Add(new WhereNode(tb_grp_article.CN_CLOSE_DATE, WhereNode.EColumnOperation.EOT_LT, typeof(tb_grp_article), DateTime.Today.AddDays(1)));
                        }
                    }
                    wnQuery.Add(new WhereNode(tb_grp_article.CN_TYPE, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), (int)Enums.ArticleType.Article));
                    wnQuery.Add(new WhereNode(tb_grp_article.CN_GROUP_UID, WhereNode.EColumnOperation.EOT_IN, typeof(tb_grp_article), lsBranch.ToArray()));
                    if (wnQuery.Any())
                    {
                        qjeArticle.wherecols = new WhereNode(WhereNode.ENodeOperation.ENO_AND, wnQuery.ToArray());
                    }
                    qjeArticle.ordercols = new List<Tuple<QueryJsonElement, string, string>> {
                        Tuple.Create(qjeArticle, tb_grp_article.CN_POST_DATE, BLWording.ORDER_DESC),
                    };

                    lBlocks.Add(qjeArticle);

                    sMsg = MakeSelectJoinByBlocks(lBlocks, out cRes);
                }
                while (false);
            }
            catch (Exception ex)
            {
                LogHelper.DBLog(Util.GetLastExceptionMsg(ex), i_nCodeLine, i_sMemberName, i_sSourcePath);
                sMsg = $"{nameof(readCommandGenerator)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(i_crmInput)}. Call from {i_sMemberName} {i_sSourcePath}({i_nCodeLine}).";
#if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif 
            }
            o_c = cRes;
            return sMsg;
        }

        protected string deleteCommandGenerator(CRequestMessage i_crmInput, JArray i_jaItems, tb_sys_session i_sSessionUser, out List<Command> o_lcResult, List<string> i_saQryContainKeys,
    [System.Runtime.CompilerServices.CallerLineNumber] int i_nCodeLine = 0,
    [System.Runtime.CompilerServices.CallerMemberName] string i_sMemberName = "",
    [System.Runtime.CompilerServices.CallerFilePath] string i_sSourcePath = "")
        {
            string sMsg = null;
            List<Command> lcCmds = new List<Command>();

            try
            {
                do
                {
                    foreach (JToken jtkItem in i_jaItems)
                    {
                        Dictionary<string, object> dicItem = jtkItem.ToObject<Dictionary<string, object>>();

                        sMsg = getManualLog(i_crmInput, dicItem, BLWording.LOG_ACTION_NAME_DELETESQL, out Command cLog);

                        if (sMsg != null)
                        {
                            break;
                        }

                        if (cLog != null)
                        {
                            lcCmds.Add(cLog);
                        }

                        string sMstUID = null;
                        if (dicItem.ContainsKey(BLWording.WHEREDATA) && dicItem[BLWording.WHEREDATA] is JObject wheredata)
                        {
                            Dictionary<string, object> wheredataDic = wheredata.ToObject<Dictionary<string, object>>();
                            if (wheredataDic.ContainsKey(BLWording.UID))
                            {
                                sMstUID = wheredataDic[BLWording.UID].ToString();

                                tb_grp_article t = new tb_grp_article()
                                {
                                    status_comment = BLWording.STATUS_FLAG_OFF
                                };

                                List<WhereNode> wnQuery = new List<WhereNode>();
                                wnQuery.Add(new WhereNode(tb_grp_comment.CN_STATUS, WhereNode.EColumnOperation.EOT_NEQ, typeof(tb_grp_comment), 9));
                                wnQuery.Add(new WhereNode(tb_grp_comment.CN_ARTICLE_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_comment), sMstUID));
                                WhereNode wn = new WhereNode(WhereNode.ENodeOperation.ENO_AND, wnQuery.ToArray());
                                Command c = Command.SetupDeleteCmd(wn);
                                Command tt = Command.SetupUpdateCmd(t, new WhereNode(tb_grp_article.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), sMstUID));
                                lcCmds.Add(c);
                                if (!wheredataDic.ContainsKey("type"))
                                {
                                    lcCmds.Add(tt);
                                }
                            }
                        }
                    }
                }
                while (false);
            }
            catch (Exception ex)
            {
                LogHelper.DBLog(Util.GetLastExceptionMsg(ex), i_crmInput);
                sMsg = $"{nameof(deleteCommandGenerator)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(i_crmInput)}. Call from {i_sMemberName} {i_sSourcePath}({i_nCodeLine}).";
#if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif 

            }

            o_lcResult = lcCmds;
            return sMsg;
        }

        private void SaveFbComment(string article_id)
        {
            // 取回文章ID跟UserToken
            QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
            QueryJsonElement qjeArticle = lBlocks.GetInst();
            qjeArticle.table = tb_grp_article.TABLENAME;
            qjeArticle.displaycols = new List<string>()
                {
                    tb_grp_article.CN_FB_ARTICLE_ID
                };
            qjeArticle.wherecols = new WhereNode(tb_grp_article.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), article_id);
            lBlocks.Add(qjeArticle);

            QueryJsonElement qjeGroup = lBlocks.GetInst();
            qjeGroup.table = tb_grp_group.TABLENAME;
            qjeGroup.jointable = qjeArticle;
            qjeGroup.jointype = QueryJsonElement.LEFT_JOIN;
            qjeGroup.joincols = new Dictionary<string, string> { { tb_grp_group.CN_UID, tb_grp_article.CN_GROUP_UID } };
            qjeGroup.displaycols = new List<string>()
                {
                    tb_grp_group.CN_CLIENT_SECRET,
                    tb_grp_group.CN_APP_ID
                };
            lBlocks.Add(qjeGroup);

            QueryJsonElement qjeGroupUser = lBlocks.GetInst();
            qjeGroupUser.table = tb_grp_group2user.TABLENAME;
            qjeGroupUser.jointable = qjeGroup;
            qjeGroupUser.jointype = QueryJsonElement.LEFT_JOIN;
            qjeGroupUser.joincols = new Dictionary<string, string> { { tb_grp_group2user.CN_GROUP_UID, tb_grp_group.CN_UID } };
            qjeGroupUser.displaycols = new List<string>()
                {
                    tb_grp_group2user.CN_USER_TOKEN
                };
            qjeGroupUser.wherecols = new WhereNode(tb_grp_group2user.CN_STATUS_FLAG, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), BLWording.STATUS_FLAG_ON);
            lBlocks.Add(qjeGroupUser);

            string sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);

            if (sMsg != null)
            {
                return;
            }
            ArsenalInterface ai = ArsenalDBMgr.GetInst(cRes);
            List<GroupViewModel2> qdArticle = ai.RunQueryList<GroupViewModel2>(cRes);

            string isValid = new FbHelper().CallFbCheckTokenGetAPI(qdArticle.First().user_token, qdArticle.First().app_id, qdArticle.First().client_secret, out int status);
            if (isValid != null)
            {
                sMsg = isValid;
                if (status == 2)
                {
                    return;
                }
            }
            bool success = new FbHelper().CallFbCommentGetAPI(article_id, qdArticle.First().user_token, qdArticle.First().fb_article_id, out List<tb_grp_comment> comments);
            if (success)   // 成功抓取資料
            {
                if (comments == null || comments.Count == 0)   // 無留言
                {

                }
                else   // 有留言
                {

                }
            }
            else   // 無法從FB抓取資料
            {

            }
        }




        /// <summary>
        /// 傳回商品資訊
        /// </summary>
        /// <param name="i_crmInput"></param>
        /// <returns></returns>
        public CResponseMessage FetchCommentFromFB(CRequestMessage i_crmInput)
        {
            string sMsg = null;
            CResponseMessage crmRes = null;
            try
            {
                do
                {
                    sMsg = getCommonParameter(i_crmInput, BLWording.QRY_MASTER, out JArray jaDataArray, out tb_sys_session sUserSession);
                    if (sMsg != null)
                    {
                        break;
                    }
                    if (jaDataArray.Count != 1 || jaDataArray[0] == null)
                    {
                        sMsg = MessageWording.PARAM_NOT_EXPECTED;
                        break;
                    }

                    var article_uid = jaDataArray[0][BLWording.WHEREDATA][BLWording.UID].ToString();

                    SaveFbComment(article_uid);
                }
                while (false);
            }
            catch (Exception ex)
            {
                sMsg = $"{nameof(FetchCommentFromFB)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(ex)}.";
                Logger.Error(ex);
                Logger.Error($"{nameof(FetchCommentFromFB)} sMsg: " + sMsg);
#if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif 
            }

            if (sMsg != null)
            {
                crmRes = new CErrorResponseMessage(sMsg, null);
            }
            else
            {
                crmRes = ReadComment(i_crmInput);
            }

            return crmRes;
        }
        class ReadCommentModel : tb_grp_article
        {
            public string fb_group_id { get; set; }
        }
        /// <summary>
        /// 傳回商品資訊
        /// </summary>
        /// <param name="i_crmInput"></param>
        /// <returns></returns>
        public CResponseMessage ReadComment(CRequestMessage i_crmInput)
        {
            string sMsg = null;
            CResponseMessage crmRes = null;
            try
            {
                do
                {
                    sMsg = getCommonParameter(i_crmInput, BLWording.QRY_MASTER, out JArray jaDataArray, out tb_sys_session sUserSession);
                    if (sMsg != null)
                    {
                        break;
                    }
                    if (jaDataArray.Count != 1 || jaDataArray[0] == null)
                    {
                        sMsg = MessageWording.PARAM_NOT_EXPECTED;
                        break;
                    }

                    var article_uid = jaDataArray[0][BLWording.WHEREDATA][BLWording.UID].ToString();

                    // 取得貼文的post_status與group_id
                    QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();
                    QueryJsonElement qjeArticle = lBlocks.GetInst();
                    qjeArticle.table = tb_grp_article.TABLENAME;
                    qjeArticle.displaycols = new List<string>()
                    {
                        tb_grp_article.CN_POST_STATUS,
                    };
                    qjeArticle.wherecols = new WhereNode(tb_grp_article.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_article), article_uid);
                    lBlocks.Add(qjeArticle);

                    // 需判斷該會員是否為此社團
                    QueryJsonElement qjeGroup = lBlocks.GetInst();
                    qjeGroup.table = tb_grp_group.TABLENAME;
                    qjeGroup.jointable = qjeArticle;
                    qjeGroup.jointype = QueryJsonElement.LEFT_JOIN;
                    qjeGroup.joincols = new Dictionary<string, string>() {
                             {  tb_grp_group.CN_UID, tb_grp_article.CN_GROUP_UID }};
                    qjeGroup.displaycols = new List<string>()
                    {
                        tb_grp_group.CN_FB_GROUP_ID,
                    };
                    lBlocks.Add(qjeGroup);

                    sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cResArticle);

                    ArsenalInterface ai = ArsenalDBMgr.GetInst(cResArticle);
                    List<ReadCommentModel> articles = ai.RunQueryList<ReadCommentModel>(cResArticle);

                    /**開始組指令**/
                    lBlocks = new QueryJsonElementCollection();

                    QueryJsonElement qjeArticleToProduct = lBlocks.GetInst();
                    qjeArticleToProduct.table = tb_grp_comment.TABLENAME;
                    qjeArticleToProduct.displaycols = new List<string>()
                    {
                        tb_grp_comment.CN_UID,
                        tb_grp_comment.CN_ARTICLE_UID,
                        tb_grp_comment.CN_ORIGIN_COMMENT,
                        tb_grp_comment.CN_COMMENT,
                        tb_grp_comment.CN_COMMENT_TIME,
                        tb_grp_comment.CN_GROUP_USER_ID,
                        tb_grp_comment.CN_STATUS,
                        tb_grp_comment.CN_USER_NAME,
                        tb_grp_comment.CN_USER_PICTURE,
                        tb_grp_comment.CN_FB_COMMENT_ID,
                        tb_grp_comment.CN_PARENT_COMMENT_ID,
                    };
                    List<WhereNode> wnCommentQuery = new List<WhereNode>
                    {
                        new WhereNode(tb_grp_comment.CN_ARTICLE_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_comment), article_uid),
                        new WhereNode(tb_grp_comment.CN_STATUS, WhereNode.EColumnOperation.EOT_NEQ, typeof(tb_grp_comment), (int)FbHelper.CommentStatus.TransferOrder),
                        new WhereNode(tb_grp_comment.CN_STATUS_FLAG, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_comment), BLWording.STATUS_FLAG_ON)
                    };
                    qjeArticleToProduct.wherecols = new WhereNode(WhereNode.ENodeOperation.ENO_AND, wnCommentQuery.ToArray());
                    // Sort
                    List<Tuple<QueryJsonElement, string, string>> qjeArticleToProductOrder = new List<Tuple<QueryJsonElement, string, string>>() {
                        Tuple.Create(qjeArticle, tb_grp_comment.CN_COMMENT_TIME, BLWording.ORDER_ASC)
                    };
                    qjeArticleToProduct.ordercols = qjeArticleToProductOrder;

                    lBlocks.Add(qjeArticleToProduct);

                    QueryJsonElement qjeMember = lBlocks.GetInst();
                    qjeMember.table = tb_meb_member.TABLENAME;
                    qjeMember.jointable = qjeArticleToProduct;
                    qjeMember.jointype = QueryJsonElement.LEFT_JOIN;
                    qjeMember.joincols = new Dictionary<string, string>() {
                             {  tb_meb_member.CN_GROUP_USER_ID, tb_grp_comment.CN_GROUP_USER_ID }};
                    qjeMember.displaycols = new List<string>()
                    {
                        tb_meb_member.CN_NAME,
                        tb_meb_member.CN_FB_PIC,
                        tb_meb_member.CN_STATUS_FLAG,
                        tb_meb_member.CN_GROUP_ID,
                        tb_meb_member.CN_DEFAULT_BRANCH
                    };
                    qjeMember.aliascols = new Dictionary<string, List<string>>
                    {
                         { tb_meb_member.CN_UID, new List<string>() { "member_uid" } }
                    };
                    List<WhereNode> wnMemberQuery = new List<WhereNode>
                    {
                        new WhereNode(tb_meb_member.CN_GROUP_ID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_meb_member), articles[0].fb_group_id),
                        new WhereNode(tb_meb_member.CN_GROUP_ID, WhereNode.EColumnOperation.EOT_ISNULL, typeof(tb_meb_member))
                    };
                    qjeMember.wherecols = new WhereNode(WhereNode.ENodeOperation.ENO_OR, wnMemberQuery.ToArray());
                    lBlocks.Add(qjeMember);

                    sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);

                    if (sMsg != null)
                    {
                        break;
                    }
                    ai = ArsenalDBMgr.GetInst(cRes);
                    List<CommentViewModel> qdArticle = ai.RunQueryList<CommentViewModel>(cRes);
                    var parentData = qdArticle.GroupBy(x => x.parent_comment_id);
                    if (!cRes.IsSuccess)
                    {
                        sMsg = cRes.LastErrorCode;
                        break;
                    }

                    crmRes = new CSuccessResponseMessage(null, i_crmInput);
                    // 填寫回傳
                    crmRes.param.Add(BLWording.DATA, parentData);
                    crmRes.param.Add("post_status", articles);
                }
                while (false);
            }
            catch (Exception ex)
            {
                sMsg = $"{nameof(ReadComment)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(i_crmInput)}.";
#if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif 
            }

            if (sMsg != null)
            {
                crmRes = new CErrorResponseMessage(sMsg, null);
            }

            return crmRes;
        }
        public CResponseMessage DeleteComment(CRequestMessage i_crmInput)
        {
            string sMsg = null;
            CResponseMessage crmRes = null;
            List<Command> lcCmds = new List<Command>();
            try
            {
                do
                {
                    sMsg = getCommonParameter(i_crmInput, BLWording.DEL_MASTER, out JArray jaDataArray, out tb_sys_session sUserSession);
                    if (sMsg != null)
                    {
                        break;
                    }
                    if (jaDataArray.Count != 1 || jaDataArray[0] == null)
                    {
                        sMsg = MessageWording.PARAM_NOT_EXPECTED;
                        break;
                    }

                    var uid = jaDataArray[0][BLWording.WHEREDATA][BLWording.UID].ToString();
                    tb_grp_comment u = new tb_grp_comment()
                    {
                        status_flag = BLWording.STATUS_FLAG_OFF
                    };
                    Command c = Command.SetupUpdateCmd(u, new WhereNode(tb_grp_comment.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_comment), uid));
                    lcCmds.Add(c);
                    ArsenalInterface ai = ArsenalDBMgr.GetInst(lcCmds[0], GetDefaultSystemColumnInfo());
                    ai.RunEditCmds(lcCmds);
                    sMsg = GetLastErrorCode(lcCmds);
                    if (sMsg != null)
                    {
                        crmRes = new CErrorResponseMessage(sMsg, null);
                    }
                    else
                    {
                        crmRes = new CSuccessResponseMessage(null, i_crmInput);
                    }
                }
                while (false);
            }
            catch (Exception ex)
            {
                sMsg = $"{nameof(DeleteComment)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(i_crmInput)}.";
#if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif
            }

            if (sMsg != null)
            {
                crmRes = new CErrorResponseMessage(sMsg, null);
            }

            return crmRes;
        }
        public CResponseMessage CreateComment(CRequestMessage i_crmInput)
        {
            string sMsg = null;
            CResponseMessage crmRes = null;
            try
            {
                do
                {
                    sMsg = getCommonParameter(i_crmInput, BLWording.ADD_MASTER, out JArray jaDataArray, out tb_sys_session sUserSession);
                    if (sMsg != null)
                    {
                        break;
                    }

                    var article = jaDataArray[0][BLWording.DATA]["article_data"].ToObject<tb_grp_article>();
                    var member = jaDataArray[0][BLWording.DATA]["member_data"].ToObject<tb_meb_member>();
                    var comment = jaDataArray[0][BLWording.DATA][BLWording.DATA].ToString();
                    List<Command> lCmds = new List<Command>();
                    var comments = new List<tb_grp_comment>();

                    // 取回該社團可以取貨的地點
                    var branches = GetBranches(article.group_uid).Select(x => x.branch_name).ToList();
                    var products = GetProducts(article.uid);                  
                    var productInfos = GetProductInfos(products);

                    Logger.Info($"開始解析貼文  文章ID: {article.uid}  設定: {JsonConvert.SerializeObject(productInfos)}");

                    var parser = new GroupBuyParser.GroupBuyParser
                    {
                        Settings = new GroupBuyParser.ParserSettings
                        {
                            Products = productInfos,
                            Branches = branches
                        }
                    };

                    if(member == null)
                    {
                        return new CErrorResponseMessage("沒有設定會員名稱", null);
                    }

                    // 如果取不回fb_id(使用者沒有允許應用程式查看貼文)仍要處理
                    string group_user_id = member.group_user_id;

                    string json = "";
                    int status = 0;
                    var parseData = parser.Parse(comment);
                    if (parseData.Success)
                    {
                        bool isProductCorrect = true;
                        foreach (var product in parseData.Product)
                        {
                            if (product.Name == "I")
                            {
                                isProductCorrect = false;
                                break;
                            }
                        }
                        if (isProductCorrect) // 名稱有I 不Insert進資料庫
                        {
                            json = JsonConvert.SerializeObject(parseData.Product);
                            status = (int)CommentStatus.OK;
                        }
                        else
                        {
                            status = (int)CommentStatus.InvalidFormat;
                        }
                    }
                    else
                    {
                        status = (int)CommentStatus.InvalidFormat;
                        // 增加log紀錄確認解析失敗的原因
                        Logger.Info($"解析貼文失敗  姓名: {member.name}  內容: {comment}  原因: {parseData.ErrorMessage}   貼文ID: {article.uid}");
                    }
                    if (string.IsNullOrEmpty(group_user_id))
                    {
                        status = (int)CommentStatus.UnknownMember;
                    }

                    tb_grp_comment cNew = new tb_grp_comment
                    {
                        uid = Guid.NewGuid().ToString(),
                        article_uid = article.uid,
                        origin_comment = comment,
                        comment = json,
                        group_user_id = group_user_id,
                        comment_time = DateTime.Now,
                        fb_comment_id = null,
                        status = status,
                        user_name = member.name,
                        user_picture = member.fb_pic
                    };
                    comments.Add(cNew);

                    // 沒有任何留言就不處理
                    if (comments.Count == 0)
                    {
                        return null;
                    }
                    lCmds.AddRange(comments.Select(x => Command.SetupInsertCmd(x)));

                    var ai = ArsenalDBMgr.GetInst(lCmds[0], GetDefaultSystemColumnInfo());
                    ai.RunEditCmds(lCmds);
                    sMsg = GetLastErrorCode(lCmds);
                    if (sMsg != null)
                    {
                        crmRes = new CErrorResponseMessage(sMsg, null);
                    }
                    else
                    {
                        crmRes = new CSuccessResponseMessage(null, i_crmInput);
                    }
                }
                while (false);
            }
            catch (Exception ex)
            {
                sMsg = $"{nameof(DeleteComment)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(i_crmInput)}.";
#if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif
                Logger.Error(ex.ToString());
            }

            if (sMsg != null)
            {
                crmRes = new CErrorResponseMessage(sMsg, null);
            }

            return crmRes;
        }

        /// <summary>
        /// 參考 CreateComment
        /// </summary>
        /// <param name="i_crmInput"></param>
        /// <returns></returns>
        public CResponseMessage ImportComment(CRequestMessage i_crmInput)
        {
            string sMsg = null;
            CResponseMessage crmRes = null;
            var logInfos = new StringBuilder();

            try
            {
                do
                {
                    sMsg = getCommonParameter(i_crmInput, BLWording.ADD_MASTER, out JArray jaDataArray, out tb_sys_session sUserSession);
                    if (sMsg != null) break;

                    var article = jaDataArray[0][BLWording.DATA]["article_data"].ToObject<tb_grp_article>();
                    var comments = jaDataArray[0][BLWording.DATA][BLWording.DATA].ToString().Split('\n');
                    var tb_grp_comment_List = new List<tb_grp_comment>();
                    var misMatchMembers = new StringBuilder();                    
                    List<Command> lCmds = new List<Command>();
                    
                    // 取回該社團可以取貨的地點
                    var branches = GetBranches(article.group_uid);            
                    var products = GetProducts(article.uid);
                    var members = GetMembers(article.group_uid);                    
                    var productInfos = GetProductInfos(products);// 將名稱以['A', 'B'...]這樣依序產生,如果產品有3個,就要放入['A', 'B', 'C']

                    logInfos.AppendLine($"{nameof(ImportComment)} 開始解析貼文留言  文章ID: {article.uid}  設定: {JsonConvert.SerializeObject(productInfos)}");
                    var parser = new GroupBuyParser.GroupBuyParser
                    {
                        Settings = new GroupBuyParser.ParserSettings
                        {
                            Products = productInfos,
                            Branches = branches.Select(x => x.branch_name).ToList()
                        }
                    };
   
                    // 去除匯入留言前面的空白行
                    var blankLineCount = 0;
                    foreach (var comment in comments)
                    {
                        if (!string.IsNullOrWhiteSpace(comment)) break;

                        blankLineCount++;
                    }
                    comments = comments[(blankLineCount)..(comments.Count())];

                    var sortMillsecond = 0;// 累加毫秒數, 用來排序正確留言順序
                    List<(string member, string orders)> membersAndOrders = new List<(string, string)>();
                    
                    // Parse comment                    
                    for (int i = 1; i < comments.Length; i++)
                    {
                        var parserData = ParserComment(parser, comments[i], branches.First().branch_name);

                        if (!parserData.Success) continue;

                        string orders = parserData.Text;
                        string member = comments[i - 1];// 往上抓客人名稱

                        // 往下抓可能有多行的訂單
                        for (++i; i < comments.Length; i++)
                        {
                            parserData = ParserComment(parser, comments[i], branches.First().branch_name);

                            if (!parserData.Success) break;

                            orders += parserData.Text;
                        }

                        membersAndOrders.Add((member, orders));
                    }

                    // Match member & default branch
                    foreach (var memberAndOrders in membersAndOrders)
                    {
                        var member = members.Find(item => item.name == memberAndOrders.member);

                        if (member == null)// 沒匹配的會員名稱
                        {
                            misMatchMembers.AppendLine($"[{memberAndOrders.orders}] ");
                            continue;
                        }

                        int status = (int)CommentStatus.UnknownMember;
                        var json = "";
                        var parseData = ParserComment(parser, memberAndOrders.orders, $"{branches.Find(x => x.uid == member.default_branch)?.branch_name}");// 匯入留言後面加上預設分店中文名稱
                        if (parseData.Success)
                        {
                            bool isProductCorrect = true;                           
                            isProductCorrect = parseData.Product.Find(x => x.Name == "I") == null ? true : false;

                            if (isProductCorrect) // 名稱有I 不Insert進資料庫
                            {
                                var Branch = branches.Find(item => item.uid == member.default_branch)?.branch_name;// Parser解析Branch會為null, 經討論後都放預設分店
                                parseData.Product.ForEach(item => item.Branch = Branch);
                                json = JsonConvert.SerializeObject(parseData.Product);
                                status = (int)CommentStatus.OK;
                            }
                            else
                            {
                                status = (int)CommentStatus.InvalidFormat;
                            }
                        }
                        else
                        {
                            status = (int)CommentStatus.InvalidFormat;
                            logInfos.AppendLine($"{nameof(ImportComment)} 解析貼文失敗  內容: {memberAndOrders.orders}  原因: {parseData.ErrorMessage}   貼文ID: {article.uid}");
                        }

                        tb_grp_comment cNew = new tb_grp_comment
                        {
                            uid = Guid.NewGuid().ToString(),
                            article_uid = article.uid,
                            origin_comment = memberAndOrders.orders,
                            comment = string.IsNullOrWhiteSpace(json) ? "" : json,
                            group_user_id = member.group_user_id,
                            comment_time = DateTime.Now.AddMilliseconds(sortMillsecond++),
                            fb_comment_id = null,
                            status = status,
                            user_name = member.name,
                            user_picture = member.fb_pic,
                        };
                        tb_grp_comment_List.Add(cNew);
                    }
                
                    if (tb_grp_comment_List.Count == 0)
                    {
                        sMsg = "沒有要匯入的留言";
                        break;
                    }
                    lCmds.AddRange(tb_grp_comment_List.Select(x => Command.SetupInsertCmd(x)));

                    var ai2 = ArsenalDBMgr.GetInst(lCmds[0], GetDefaultSystemColumnInfo());
                    ai2.RunEditCmds(lCmds);
                    sMsg = GetLastErrorCode(lCmds);
                    if (sMsg != null)
                    {
                        break;
                    }

                    if (!string.IsNullOrWhiteSpace(misMatchMembers.ToString()))
                    {
                        misMatchMembers.Insert(0, "以下下單會員資料查詢不到, 不匯入系統: ");
                    }

                    crmRes = new CSuccessResponseMessage(misMatchMembers.Insert(0, "匯入成功 ").ToString(), i_crmInput);
                }
                while (false);
            }
            catch(Exception ex)
            {
                sMsg = $"{nameof(DeleteComment)} unknwon exception. i_crmInput={JsonConvert.SerializeObject(i_crmInput)}.";
                #if DEBUG
                System.Diagnostics.Debug.WriteLine(sMsg);
#endif
                Logger.Error(ex.ToString());
            }
            finally
            {
                Logger.Info(logInfos.ToString());
            }

            if (sMsg != null)
            {
                crmRes = new CErrorResponseMessage(sMsg, null);
            }

            return crmRes;
        }

        private List<tb_prd_article2product> GetProducts(string article_uid)
        {
            /**開始組指令**/
            QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();

            QueryJsonElement qjeArticleToProduct = lBlocks.GetInst();
            qjeArticleToProduct.table = tb_prd_article2product.TABLENAME;
            qjeArticleToProduct.displaycols = new List<string>()
            {
                tb_prd_article2product.CN_UID,
                tb_prd_article2product.CN_NAME,
                tb_prd_article2product.CN_PRICE,
                tb_prd_article2product.CN_SEQ,
                tb_prd_article2product.CN_SPECIFICATION
            };
            qjeArticleToProduct.wherecols = new WhereNode(tb_prd_article2product.CN_ARTICLE_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_prd_article2product), article_uid);
            lBlocks.Add(qjeArticleToProduct);

            QueryJsonElement qjeProduct = lBlocks.GetInst();
            qjeProduct.table = tb_prd_product.TABLENAME;
            qjeProduct.jointable = qjeArticleToProduct;
            qjeProduct.joincols = new Dictionary<string, string>()
            {
                 {  tb_prd_product.CN_UID, tb_prd_article2product.CN_PRD_UID }
            };
            lBlocks.Add(qjeProduct);

            var sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);
            var ai = ArsenalDBMgr.GetInst(cRes);
            List<tb_prd_article2product> data = ai.RunQueryList<tb_prd_article2product>(cRes);

            return data.ToList();
        }
        private List<tb_grp_branch> GetBranches(string group_uid)
        {
            tb_grp_branch cDisplay = new tb_grp_branch();
            cDisplay.SetFullDirty();
            var whereNode = new WhereNode(tb_grp_branch.CN_GROUP_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_grp_comment), group_uid);
            var cSelect = Command.SetupSelectCmd(cDisplay, whereNode);
            var ai = ArsenalDBMgr.GetInst(cSelect);
            var data = ai.RunQueryList<tb_grp_branch>(cSelect);

            return data;
        }

        public List<tb_meb_member> GetMembers(string group_uid_)
        {
            QueryJsonElementCollection lBlocks = new QueryJsonElementCollection();

            QueryJsonElement qjeMember = lBlocks.GetInst();
            qjeMember.table = tb_meb_member.TABLENAME;
            qjeMember.displaycols = new List<string>()
                    {
                        tb_meb_member.CN_UID,
                        tb_meb_member.CN_NAME,
                        tb_meb_member.CN_GROUP_ID,
                        tb_meb_member.CN_DEFAULT_BRANCH,
                        tb_meb_member.CN_GROUP_USER_ID,
                        tb_meb_member.CN_FB_PIC
                    };
            //qjeMember.wherecols = new WhereNode(tb_meb_member.CN_GROUP_ID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_meb_member), article.group_uid);
            lBlocks.Add(qjeMember);

            QueryJsonElement qjeProduct = lBlocks.GetInst();
            qjeProduct.table = tb_grp_group.TABLENAME;
            qjeProduct.jointable = qjeMember;
            qjeProduct.joincols = new Dictionary<string, string>()
                    {
                            {  tb_grp_group.CN_FB_GROUP_ID, tb_meb_member.CN_GROUP_ID }
                    };
            qjeProduct.wherecols = new WhereNode(tb_grp_group.CN_UID, WhereNode.EColumnOperation.EOT_EQ, typeof(tb_meb_member), group_uid_);
            lBlocks.Add(qjeProduct);

            var sMsg = MakeSelectJoinByBlocks(lBlocks, out Command cRes);

            if (!string.IsNullOrWhiteSpace(sMsg))
            {
                throw new Exception(sMsg);
            }

            var ai = ArsenalDBMgr.GetInst(cRes);
            return ai.RunQueryList<tb_meb_member>(cRes);
        }

        /// <summary>
        /// 使用原本解析器, 加上隨意的預設分店防止錯誤訊息跳出   
        /// </summary>
        /// <param name="branch_name"></param>
        /// <param name="comment"></param>
        /// <param name="parser"></param>
        /// <returns></returns>
        private GroupBuyParser.ParserData ParserComment(GroupBuyParser.GroupBuyParser parser, string comment, string branch_name)
        {
            var parserData = new GroupBuyParser.ParserData() { DefaultBranch = branch_name };
            parserData.Text = comment;
            parser.Parse(parserData);

            return parserData;
        }

        /// <summary>
        /// 條列A~Z項目時要忽略I項目, Example: ABCDEFGH >>> JKL, 屬於客製化設計
        /// </summary>
        /// <param name="products"></param>
        /// <returns></returns>
        private List<GroupBuyParser.ProductInfo> GetProductInfos(List<tb_prd_article2product> products)
        {
            return products.Select((x, i) => new GroupBuyParser.ProductInfo
            {
                Name = ((char)('A' + (i < 8 ? i : i + 1))).ToString(),// Jump over product items [ I ], Name = ABCDEFGHJ.....etc
                Specifications = string.IsNullOrEmpty(x.specification) ? null : x.specification.Split(',', StringSplitOptions.RemoveEmptyEntries)
            }).ToList();
        }
    }
}