using Edge.Core.Processor;using Edge.Core.IndustryStandardInterface.Pump;
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading.Tasks;
using System.Xml;
using System.Xml.Linq;
using Wayne.FDCPOSLibrary;

namespace Dfs.WayneChina.HyperPrinterHandler
{
    /// <summary>
    /// Entity to communicate to a proxy on Screen App to send the receipt to the printer on dispenser.
    /// </summary>
    public class PrinterHandler : IAppProcessor, IFdcCommunicableController
    {
        #region IFdcCommunicableController implementation

        
        public string MetaConfigName { get; set; }
        public Func<string, bool> BroadcastMessageViaFdc { get; set; }

        public Func<string, string, string, bool> SendMessageViaFdc { get; set; }

        public Func<string, Tuple<string, OverallResult>> OnMessageReceivedViaFdc { get; set; }

        #endregion

        #region IApplication implementaion

        public void Init(IEnumerable<IProcessor> processors)
        {

        }

        public Task<bool> Start()
        {
            return Task.FromResult(true);
        }

        public Task<bool> Stop()
        {
            return Task.FromResult(true);
        }

        #endregion

        #region Fields

        private static int request = 0;

        private const string newLineCmd = "0A";

        private const string cutPaperCmd = "1D564200";

        #endregion

        #region Logger

        NLog.Logger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetLogger("HyperPrinter");

        #endregion

        #region Constructor

        public PrinterHandler(int id, int maxLength)
        {
            //Receive HTML receipt from `On Screen POS`
            OnMessageReceivedViaFdc += HandlePrintingRequestFromOnScreenPos;
        }

        #endregion

        private Tuple<string, OverallResult> HandlePrintingRequestFromOnScreenPos(string message)
        {
            var htmlReceipt = message;

            if (!string.IsNullOrEmpty(htmlReceipt))
            {
                logger.Info(htmlReceipt);

                if (htmlReceipt.Contains("<TransactionOperation"))
                {
                    logger.Info("Received printing request from screen");

                    try
                    {
                        XmlDocument doc = new XmlDocument();
                        doc.LoadXml(htmlReceipt);
                        var nozzleNoAttribute = doc.DocumentElement.Attributes["NozzleNo"];
                        int nozzleNo = Convert.ToInt32(nozzleNoAttribute.Value);
                        //Console.WriteLine($"NozzleNo: {nozzleNo}");

                        var operationTypeAttribute = doc.DocumentElement.Attributes["OpType"];
                        string opType = operationTypeAttribute.Value;
                        //Console.WriteLine($"Operation type: {opType}");

                        var receiptHtmlAttribute = doc.DocumentElement.Attributes["ReceiptString"];
                        string receiptHtml = receiptHtmlAttribute.Value;
                        //Console.WriteLine($"Receipt HTML: {receiptHtml}");

                        SendFormattedReceipt(Convert.ToInt32(nozzleNo), receiptHtml);
                    }
                    catch (Exception ex)
                    {
                        logger.Info($"Parsing TransactionOperation request from On Screen POS: {ex}");
                        return new Tuple<string, OverallResult>("Shit", OverallResult.Failure);
                    }

                    return new Tuple<string, OverallResult>("I have received your receipt", OverallResult.Success);
                }
                else if (htmlReceipt.Contains("<DisplayResponse"))
                {
                    logger.Info("Sending out receipt got acked");

                    try
                    {
                        logger.Info($"Got display response: {htmlReceipt}");
                    }
                    catch (Exception ex)
                    {
                        logger.Error($"Parsing Display response: {ex}");
                        return new Tuple<string, OverallResult>("DisplayResponse, run into expcetion", OverallResult.Failure);
                    }

                    return new Tuple<string, OverallResult>("OK", OverallResult.Success);
                }
            }

            return new Tuple<string, OverallResult>("Received unrecognized message", OverallResult.Failure);
        }

        /// <summary>
        /// Send the printer specific receipt raw bytes to the pump printer via 'On Screen POS'
        /// </summary>
        /// <param name="nozzleNo">The associated nozzle number.</param>
        /// <param name="htmlReceipt">expected format for this part like ""</param>
        public void SendFormattedReceipt(int nozzleNo, string htmlReceipt)
        {
            var receiptContext = GetFormattedReceipt(htmlReceipt, nozzleNo);
            //var sent = SendMessageViaFdc.Invoke("100", $"Nozzle {nozzleNo}", receiptContext);

            if (receiptContext != null)
            {
                var sent = BroadcastMessageViaFdc(receiptContext);
                logger.Info($"sent out receipt: {receiptContext}, result success? {sent}");
            }
        }

        private string FormatReceiptFromHtml(string htmlReceipt)
        {
            logger.Info("receipt test begins....");
            return GetFormattedReceipt(htmlReceipt);
        }

        private int GetNextRequestId()
        {
            return request++;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="rawData"></param>
        /// <param name="nozzleNo"></param>
        /// <returns></returns>
        private string GetFormattedReceipt(string rawData, int nozzleNo = 1)
        {
            logger.Info("Receipt HTML data: " + rawData);

            try
            {
                var receiptLineItems = (new Parser()).ParseToReceiptLineItems(System.Web.HttpUtility.HtmlDecode(rawData));
                string receiptForPrinter = string.Empty;
                List<string> receipt = new List<string>();
                foreach (var rl in receiptLineItems)
                {
                    receipt.AddRange(rl.Format());
                }

                foreach (var text in receipt)
                {
                    receiptForPrinter += text;
                    receiptForPrinter += newLineCmd;
                }

                //add an additional empty line
                for (int i = 0; i < 32; i++)
                {
                    receiptForPrinter += "20";
                }

                receiptForPrinter += newLineCmd;
                receiptForPrinter += cutPaperCmd;

                XDocument doc = new XDocument();
                var rootElement = new XElement("Display");
                rootElement.Add(new XAttribute("RequestId", GetNextRequestId()));
                rootElement.Add(new XAttribute("NozzleNo", nozzleNo));
                rootElement.Add(new XAttribute("FormattedReceiptString", receiptForPrinter));
                doc.Add(rootElement);

                return doc.ToString();
            }
            catch (Exception ex)
            {
                logger.Info($"Create receipt exception: {ex}");
            }

            return string.Empty;
        }

        public string ByteArrayToString(byte[] ba)
        {
            return BitConverter.ToString(ba).Replace("-", "");
        }

    }
}