using System.Collections.Generic;
using Platform.Library;
using Platform.Print;
using TellerSystem.Contract.ContractBase;
using TellerSystem.Contract.Contracts;
using TellerSystem.Library.Ext.Function;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
using TellerSystem.Contract.Function;
using TellerSystem.ServiceProxy.Ext.ServiceEntitys;
using Platform.Common.RunningParameters;
using TellerSystem.ServiceProxy.Ext.ServiceHelper;
using System.Windows;
using TellerSystem.Library.Ext.TradeExtension;
using TellerSystem.PrintTemplate.Extension;
using TellerSystem.PrintTemplate.PrintTemplateData;
using System;
using Platform.Common.LogSystem;
using TellerSystem.Communication;
using System.Text;
using TellerSystem.Communication.SocketListener;
using System.Linq;
using TellerSystem.ServiceProxy.Ext.TradeBusinessEntitys;
using TellerSystem.ServiceProxy.Ext;
using System.Diagnostics;
using System.Text.RegularExpressions;

namespace TellerSystem.Contract.Entry
{
    /// <summary>
    ///     提交逻辑入口
    /// </summary>
    public abstract class SubmitEntry : PrintflowEntry
    {
        #region 控制
        /// <summary>
        /// 提交标识，当提交成功后将变为true
        /// </summary>
        public bool Submitted { get; private set; }

        /// <summary>
        ///     是否自定义检测通讯返包
        /// </summary>
        public bool IsCustomizeVerify { get; protected set; }

        /// <summary>
        ///     自动检测通讯返包
        /// </summary>
        /// <returns></returns>
        private bool AutoVerify()
        {
            //定制通讯失败情况下的通知方式
            if (MessageData.Fd12 != "0000")
            {
                PageData.TradeAPIs.ShowErrorMessageBox(PageData.GetError(MessageData));
                return false;
            }
            return true;
        }

        #endregion

        #region 公开方法

        /// <summary>
        ///     执行提交流程
        /// </summary>
        /// <returns></returns>
        public bool RaiseSubmit()
        {
            //条件检测
            if (MessageData == null || PageData == null || Submitted) return false;
            //填充公共数据
            var SerialNumber = PageData.CreateSerialNumber();
            if (string.IsNullOrWhiteSpace(SerialNumber))//校验前端流水是否产生
            {
                return false;
            }
            if (SerialNumber.Length > 8)
            {
                MessageData.Fd96_Q = SerialNumber.Substring(8);
            }
            AuthDataHelper authdata = new AuthDataHelper(PageData);
            CheckDataHelper checkdata = new CheckDataHelper(PageData);
            if (!string.IsNullOrEmpty(checkdata.SuperTeller)) //复核柜员
            {
                MessageData.Fd8 = checkdata.SuperTeller;
            }
            if (!string.IsNullOrEmpty(authdata.AuthTeller)) //授权柜员
            {
                MessageData.Fd9_1 = authdata.AuthTeller;
            }
            //核心需要记录交易号
            MessageData.Fd14 = PageData.TradeModel.Code;

            #region 考试系统相关begin
            //考试系统相关:存储发送报文，用于后面发送至考试系统
            string SendMessage = string.Empty;
            if (ExamSystem.Instance.InExamMode)
                SendMessage = ExamSystem.Instance.KGetMessageString(MessageData, "发送");
            #endregion 考试系统相关end

            //设定通讯流水，用于登记报文。通讯完毕后解除，防止重复登记
            MessageData.SerialNumber = this.TradeInfo.SystemSerialNumber;
            //登记打印数据
            if (!this.StashPrintData())
                return false;
            //执行通讯操作
            var flag = PageData.DoTransit(MessageData);
            MessageData.SerialNumber = string.Empty;
            //if (!flag)
            //{
            //    MessageBoxResult result = this.TradeAPIs.ShowWarnMessageBox("提交交易不成功, 为了避免重复提交\n请查看该笔业务流程是否已经完成!");
            //    PlatformLogger.TradeInfo("提交交易不成功,为了避免重复提交</n>请主动去查看该笔业务流程是否已经完成!\n前端流水号：" + SerialNumber + "\n操作柜员:" + MessageData.Fd7);
            //    TradeHandle.WriteImportantLog(SerialNumber + "提交交易无法确认状态", "通讯返回false，请检查网络", this.PageData.TradeModel.Code, "RaiseSubmit", "1", string.Join(",", SocketManager.GetLocalIpAddressList()));
            //    this.PageData.Close();
            //    return false;
            //}
            #region 考试系统相关begin
            //将通讯返回的Message对象进行处理后，发送至考试系统
            string ReceiveMessage = string.Empty;
            if (ExamSystem.Instance.InExamMode)
            {
                ReceiveMessage = ExamSystem.Instance.KGetMessageString(MessageData, "返回");
                ExamSystem.Instance.SendExamData(SendMessage, ReceiveMessage, this.TradeInfo.TradeCode, this.TradeInfo.SystemSerialNumber ?? string.Empty);
            }
            #endregion 考试系统相关end

            //通讯成功后，进行结果判定
            //通讯之后的逻辑，务必保证正常出票
            if (IsCustomizeVerify)
            {
                if (!SubmitComplete())
                    return false;
            }
            else
            {
                if (!flag)
                {
                    MessageBoxResult result = this.TradeAPIs.ShowWarnMessageBox("提交交易不成功, 为了避免重复提交\n请查看该笔业务流程是否已经完成!");
                    PlatformLogger.TradeInfo("提交交易不成功,为了避免重复提交</n>请主动去查看该笔业务流程是否已经完成!\n前端流水号：" + SerialNumber + "\n操作柜员:" + MessageData.Fd7);
                    TradeHandle.WriteImportantLog(SerialNumber + "提交交易无法确认状态", "通讯返回false，请检查网络", this.PageData.TradeModel.Code, "RaiseSubmit", "1", string.Join(",", SocketManager.GetLocalIpAddressList()));
                    this.PageData.Close();
                    return false;
                }
                if (!AutoVerify()) return false;
                try
                {
                    SubmitComplete();
                }
                catch (Exception ex)
                {
                    PlatformLogger.SystemErrorInfo("SubmitEntry.RaiseSubmit方法，执行SubmitComplete发生异常！", ex);
                }
            }
            try
            {
                //标识：交易已经提交完毕
                if (!Regex.IsMatch(PageData.TradeInfo.TradeCode, ServiceProxy.Ext.ServiceSettings.GetConfig("SkipFlagSubmitted", "none")))
                    Submitted = true;
                //异常补打相关的资料上总线
                PageData.TradeBus.RecvMessage = MessageData;
                PageData.TradeBus.PageAction = PageData.GetType().ToString();
                //异步提交交易记录
                UploadData();
                //插入柜员流水
                //if (!string.IsNullOrWhiteSpace(MessageData.Fd4))
                //{
                //    PageData.CreateTellerSerialNumber(PageData.GetPrintAttributes().SystemSerialNumber);
                //}
                //回显界面
                RaiseCallbackDescription();
                this.PageData.PagePrinted += PageData_PagePrinted;
                //交易执行成功，执行打印流程
                RaisePrint();
            }
            catch (Exception ex)
            {
                this.TradeAPIs.ShowInfoMessageBox(string.Format("提交交易成功，解析返回数据出错，错误信息:\n{0}", ex.Message));
                var msgLog = GetMessageString(MessageData);
                PlatformLogger.SystemErrorInfo("提交交易成功，解析返回数据出错\n***************************************************\n" + msgLog + "\n", ex);
                TradeHandle.WriteImportantLog(SerialNumber + "提交交易成功，解析返回数据出错", ex.Message + "\n" + ex.StackTrace, this.PageData.TradeModel.Code, "RaiseSubmit", "1", string.Join(",", SocketManager.GetLocalIpAddressList()));
            }

            ////执行后续操作
            //Finally();
            PageData_PagePrinted(null, null);//补偿一次，存在未触发的bug场景。原因未知，目前观测某些情况下动态调用未正常执行
            //交易完成，清理
            TradeCompleted();
            //清除总线上授权柜员与复核柜员
            authdata.AuthTeller = string.Empty;
            authdata.AuthTeller2 = string.Empty;
            checkdata.SuperTeller = string.Empty;
            PageData.ClearSerialNumber();
            //清除柜员流水
            TradeInfoData.GetTradeInfo(PageData).SerialNumber = string.Empty;
            return true;
        }
        private bool flag2Fina11y = false;
        void PageData_PagePrinted(object sender, EventArgs e)
        {
            this.PageData.Log2PagePrinted("触发rinally" + flag2Fina11y);
            this.PageData.PagePrinted -= PageData_PagePrinted;
            if (flag2Fina11y) return;//不允许重复触发
            flag2Fina11y = true;
            Finally();
        }

        /// <summary>
        /// 根据Message对象获取对于域的值
        /// </summary>
        /// <param name="msg">Message对象</param>
        /// <returns>对于域的值</returns>
        private string GetMessageString(Message msg)
        {
            System.Reflection.PropertyInfo[] info = msg.GetType().GetProperties();
            StringBuilder strText = new StringBuilder(1000);
            for (int i = 0; i < info.Length; i++)
            {
                if (info[i].Name.StartsWith("Fd"))
                {
                    var val = info[i].GetValue(msg, null).ToString().Trim().Replace("\r", "").Replace("\n", "");
                    if (!string.IsNullOrWhiteSpace(val))
                    {
                        strText.Append("[" + info[i].Name + "=" + val + "]");
                        strText.AppendLine();
                    }
                }
            }
            return strText.ToString();
        }
        private void UploadData()
        {
            try
            {
                //组装数据
                var tradeInfo = new TellerInfo
                {
                    TellerNo = LoginUserInfo.TellerNo,
                    TradeNo = PageData.TradeModel.Code,
                    Tlrlvl = "",
                    BrNo = LoginUserInfo.KinbrNo,
                    Status = 1,      //默认为1，标明该流程为正常结束
                    BlackSerialNo2 = (MessageData.CustomizeTransitEntry != null && !string.IsNullOrEmpty(MessageData.CustomizeTransitEntry.SerialNo))
                        ? MessageData.CustomizeTransitEntry.SerialNo : MessageData.Fd126_1,//存在自定义流水号时加载
                    BlackSerialNo = MessageData.Fd4,
                    TradeFileName = this.GetType().FullName,
                    BusinessDate = LoginUserInfo.TradeDate
                };
                //如果有授权柜员或复合柜员，则需保存交易页面数据
                AuthDataHelper authdata = new AuthDataHelper(PageData);
                CheckDataHelper checkdata = new CheckDataHelper(PageData);
                byte[] pagedata = new byte[0];
                if (!string.IsNullOrEmpty(checkdata.SuperTeller) || !string.IsNullOrEmpty(authdata.AuthTeller))
                {
                    pagedata = PageData.SaveTradePage((FrameworkElement)(PageData.Content));
                }
                var tradeBus = (Dictionary<string, string>)TradeInfoData.GetTradeInfo(PageData as DependencyObject).TradeBus.Serialize();
                var serialNumber = PageData.CreateSerialNumber();
                //异步提交
                Action action = () =>
                {
                    PlatformLogger.SystemInfo("UploadData:Raise=>" + serialNumber);
                    //提交工作流，返回柜员流水号
                    WorkFlowHandle.GetWorkFlowTradeSubmit(
                                         tradeInfo, pagedata, tradeBus, "", serialNumber, false, true);
                };
                action.BeginInvoke(new AsyncCallback(x =>
                {
                    try
                    {
                        action.EndInvoke(x);
                    }
                    catch (Exception e)
                    {
                        TradeHandle.WriteImportantLog("UploadData", e.Message + "\n" + e.StackTrace, "GetWorkFlowTradeSubmitException", "0", string.Join(",", SocketManager.GetLocalIpAddressList()));
                    }
                }), null);
            }
            catch (Exception ex)
            {
                PlatformLogger.SystemErrorInfo("SubmitEntry.UploadData方法，上载交易数据发生异常！", ex);
            }
        }

        private void RaiseCallbackDescription()
        {
            //回显要素
            Dictionary<string, string> displayDesc = null;
            try
            {
                displayDesc = CreateDisplayDescription();
            }
            catch (Exception ex)
            {
                PlatformLogger.SystemErrorInfo("SubmitEntry.RaiseCallbackDescription方法，创建回显要素集合发生异常！", ex);
            }
            if (displayDesc == null)
            {
                TradeAPIs.ShowSuccessMessageBox();
            }
            else
            {
                var wrap = new WrapPanel();
                foreach (var item in displayDesc)
                {
                    wrap.Children.Add(new BulletDecorator
                    {
                        MinWidth = 350,
                        VerticalAlignment = System.Windows.VerticalAlignment.Center,
                        HorizontalAlignment = System.Windows.HorizontalAlignment.Center,
                        Bullet = new TextBlock
                        {
                            VerticalAlignment = System.Windows.VerticalAlignment.Center,
                            HorizontalAlignment = System.Windows.HorizontalAlignment.Right,
                            Text = item.Key + ":"
                        },
                        Child = new TextBlock
                        {
                            VerticalAlignment = System.Windows.VerticalAlignment.Center,
                            HorizontalAlignment = System.Windows.HorizontalAlignment.Left,
                            Text = item.Value
                        }
                    });
                }
                TradeAPIs.ShowSuccessMessageBox(wrap);
            }
        }

        /// <summary>
        ///     执行打印流程
        /// </summary>
        /// <returns></returns>
        public bool RaisePrint()
        {
            //采用新的打印流程化,暂只对提交约束页面有效
            if (PageData is ISubmitContract)
                return this.RaisePrintflow(false);//前置流程已经执行stash
            //产生打印清单
            List<PrintContainer> printList = null;
            try
            {
                if (!CreatePrintList(out printList))
                    TradeHandle.WriteImportantLog("SubmitEntry.RaisePrint方法，调用CreatePrintList方法失败！", this.MessageData.FileData, this.PageData.TradeModel.Code, "RaiseSubmit", "5", string.Join(",", SocketManager.GetLocalIpAddressList()));
            }
            catch (Exception ex)
            {
                PlatformLogger.SystemErrorInfo("SubmitEntry.RaisePrint方法，调用CreatePrintList方法发生异常！", ex);
                //提示一下
                PageData.ShowErrorMessageBox("产生凭证打印清单失败！请检查完整性...");
                TradeHandle.WriteImportantLog("SubmitEntry.RaisePrint方法，调用CreatePrintList方法发生异常！", ex.Message + "\n" + ex.StackTrace, this.PageData.TradeModel.Code, "RaiseSubmit", "5", string.Join(",", SocketManager.GetLocalIpAddressList()));
            }
            if (printList == null)
                printList = new List<PrintContainer>();
            printList.AddRange(MorePrintList);
            if (printList.Count == 0)
                return true;
            return ContractManager.RaisePrint(PageData, MessageData, printList);
        }

        private List<PrintContainer> _morePrintList = new List<PrintContainer>();

        /// <summary>
        /// 更多的打印数据
        /// </summary>
        public List<PrintContainer> MorePrintList
        {
            get { return _morePrintList; }
        }
        #endregion

        #region 抽象方法

        /// <summary>
        ///     提交完毕，并验证结果
        /// </summary>
        /// <returns></returns>
        public abstract bool SubmitComplete();

        /// <summary>
        ///     流程处理结束，执行后续操作
        /// </summary>
        /// <returns></returns>
        public abstract bool Finally();

        /// <summary>
        ///     创建打印列表，抽象成交易自身定制
        /// </summary>
        /// <returns></returns>
        public abstract bool CreatePrintList(out List<PrintContainer> printList);
        #endregion

        #region 虚方法
        /// <summary>
        /// 创建回显要素集合
        /// </summary>
        /// <returns></returns>
        public virtual Dictionary<string, string> CreateDisplayDescription()
        {
            return null;
        }

        /// <summary>
        /// 提交交易计数器
        /// </summary>
        private static int _counter = 0;

        /// <summary>
        /// 交易完毕，执行清理工作
        /// </summary>
        public virtual bool TradeCompleted()
        {
            //执行固定次数交易后，做一次打印进程清理，避免进程使用太久导致内存溢出
            _counter++;
            if (_counter % ServiceSettings.GetConfig("PrinterLoop", 99999) == 0)
            {
                Process.GetProcessesByName("Platform.PrintService").ToList().ForEach(p =>
                {
                    try
                    {
                        p.Kill();
                    }
                    catch { }
                });
                System.Threading.Thread.Sleep(500);
            }
            //交易完成，默认采用关闭交易动作
            if (string.Compare(PageData.TradeAPIs.GetTradeMetadata("isClosePage"), "true", true) == 0)
            {
                PageData.OpenPage(PageData.TradeModel.Action, null);
            }
            else
            {
                PageData.Close();
            }
            //PageData.Close();
            return true;
        }
        #endregion

        public override List<PrintContainer> GeneratePrintList()
        {
            List<PrintContainer> printList = null;
            try
            {
                var message = this.MessageData;
                if (!CreatePrintList(out printList))
                    TradeHandle.WriteImportantLog("SubmitEntry.RaisePrint方法，调用CreatePrintList方法失败！", message.FileData, this.PageData.TradeModel.Code, "RaiseSubmit", "5", string.Join(",", SocketManager.GetLocalIpAddressList()));
            }
            catch (Exception ex)
            {
                PlatformLogger.SystemErrorInfo("SubmitEntry.RaisePrint方法，调用CreatePrintList方法发生异常！", ex);
                //提示一下
                this.TradeAPIs.ShowErrorMessageBox("产生凭证打印清单失败！请检查完整性...");
                TradeHandle.WriteImportantLog("SubmitEntry.RaisePrint方法，调用CreatePrintList方法发生异常！", ex.Message + "\n" + ex.StackTrace, this.PageData.TradeModel.Code, "RaiseSubmit", "5", string.Join(",", SocketManager.GetLocalIpAddressList()));
            }
            if (printList == null)
                printList = new List<PrintContainer>();
            printList.AddRange(MorePrintList);
            return printList;
        }

        public override bool PreviewPrintflow()
        {
            return true;
        }
    }
}
