using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using SimpleHttp;
using System.Xml.Linq;
using Newtonsoft;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using BodyshopPartner.Models;
using ToastNotifications.Messages;
using System.Threading;

namespace BodyshopPartner.Utils
{
    public static class HTTPServer
    {
        private static NLog.Logger logger = NLog.LogManager.GetCurrentClassLogger();
        public delegate void HttpLogger(string s);
        private static HttpLogger hlog;
        public static CancellationTokenSource tokenSource = new CancellationTokenSource();
        public static CancellationToken token = tokenSource.Token;

        public static void InitHttpServer(HttpLogger HttpLogger)
        {
            Route.Add("/qb/", (req, res, props) =>
            {
                hlog("Received a ping from ImEX.online");
                res.WithCORS();
                //res.AddHeader("Access-Control-Allow-Origin", "http://localhost:3000 https://localhost:3000 http://localhost:5000 https://localhost:5000 https://*.imex.online,imex.online");
                res.Close();
            }, "OPTIONS");

            Route.Add("/qb/",
                (req, res, props) => { HandleQbPost(req, res); }
            , "POST");

            logger.Trace("Starting HTTP server...");
            hlog = HttpLogger;

            //TODO As a part of the installer, add netsh http add urlacl url=http://+:1337/ user="Everyone
            try
            {
                hlog("ImEX Online connection server starting...");
                HttpServer.ListenAsync(1337, token, Route.OnHttpRequestAsync).Wait();

            }
            catch (Exception Ex)
            {
                logger.Fatal("Unable to start HTTP server. " + Ex.ToString());
                App.Current.Dispatcher.Invoke(() =>
                {
                    string msg = "Unable to connect to ImEX Online Web App. Please ensure your firewall allows the connection.";
                    hlog("ImEX Online connection server could not start. Please restart the partner to try again.");
                    Utils.Notifications.notifier.ShowError(msg);
                    bool AddedException = Utils.SquirrelAwareHelper.AddHttpExcetion();

                    //Growler.AddNotification(new Notification()
                    //{
                    //    Title = Properties.Resources.Msg_NewJobUploaded,
                    //    Subtitle = item.Job?.ownr_fn?.Value + " " + item.Job?.ownr_ln?.Value + " | " + item.Job?.clm_no?.Value,
                    //    //Message = item.Job?.vehicle?.data?.v_model_yr?.Value + " " + item.Job?.vehicle?.data?.v_make_desc?.Value + " " + item.Job?.vehicle?.data?.v_model_desc?.Value
                    //});
                });
                Utils.SquirrelAwareHelper.AddHttpExcetion();
            }
        }

        private static void HandleQbPost(System.Net.HttpListenerRequest req, System.Net.HttpListenerResponse res)
        {
            logger.Trace("/qb/ - POST");
            hlog("Received QuickBooks Receivable request.");
            //Input will be an array of objects containing XMLs. 

            List<QbRequestItem> AllRequests = ParseRequest(req);
            List<QbResponseItem> HttpResponse = new List<QbResponseItem>();
            try
            {
                hlog("Connecting to QuickBooks. This may take a moment...");
                QuickBooksInterop.ConnectToQuickBooks();

                foreach (QbRequestItem request in AllRequests)
                {
                    try
                    {
                        hlog("Processing QuickBooks request. ImEX Online Record ID:" + request.Id);
                        XDocument response = XDocument.Parse(QuickBooksInterop.ProcessQBXmlRequestUnManaged(request.QbXML));
                        QbXmlResponse ResponseStatus = QuickBooksInterop.ParseResponseXml(response);

                        logger.Trace(response.ToString());
                        logger.Debug(ResponseStatus.ToString());
                        hlog(ResponseStatus.ToString());

                        QbResponseItem r = new QbResponseItem()
                        {
                            Id = request.Id,
                            Success = ResponseStatus.StatusCode == "0" || request.OkStatusCodes.Contains(ResponseStatus.StatusCode),
                            ErrorMessage = ResponseStatus.StatusMessage
                        };

                        HttpResponse.Add(r);
                    }
                    catch (Exception Ex)
                    {
                        //Shouldn't really get here unless something is malformed. 
                        logger.Error(Ex, "Error encountered when processing QbXML Request.\n {0}", request.QbXML);
                        QbResponseItem r = new QbResponseItem()
                        {
                            Id = request.Id,
                            Success = false,
                            ErrorMessage = Ex.Message
                        };

                        HttpResponse.Add(r);
                    }

                }
                QuickBooksInterop.DisconnectFromQuickBooks();

                hlog("Completed QuickBooks requests.");

            }
            catch (Exception Ex)
            {
                logger.Error(Ex, "Error encountered while processing QuickBooks requests.");
                hlog("Error encountered while processing QuickBooks requests.");
                HttpResponse.Add(new QbResponseItem() { Id = "-1", Success = false, ErrorMessage = Ex.Message });
            }
            res.WithCORS().AsText(JsonConvert.SerializeObject(HttpResponse));

        }

        public static List<QbRequestItem> ParseRequest(System.Net.HttpListenerRequest req)
        {
            System.IO.Stream body = req.InputStream;
            System.Text.Encoding encoding = req.ContentEncoding;
            System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);
            string s = reader.ReadToEnd();
            body.Close();
            reader.Close();

            return JsonConvert.DeserializeObject<List<QbRequestItem>>(s);
        }

        public static string[] ParseBodyToArray(System.Net.HttpListenerRequest req)
        {
            System.IO.Stream body = req.InputStream;
            System.Text.Encoding encoding = req.ContentEncoding;
            System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);
            string s = reader.ReadToEnd();
            body.Close();
            reader.Close();

            return JArray.Parse(s).Select(jv => jv.ToString()).ToArray();
        }

        public static string ParseBodyToString(System.Net.HttpListenerRequest req)
        {
            System.IO.Stream body = req.InputStream;
            System.Text.Encoding encoding = req.ContentEncoding;
            System.IO.StreamReader reader = new System.IO.StreamReader(body, encoding);
            string s = reader.ReadToEnd();
            body.Close();
            return s;
        }

        public static XDocument ParseStringToXml(string input)
        {
            return XDocument.Parse(input);
        }


    }
}
