using InABox.Core;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using System.Xml;

namespace InABox.API
{
    public class ASPSMSProvider : ISMSProvider
    {
        private static int aspPort = 5061;
        private static string aspHost = "xml3.aspsms.com";
        private static string aspUrl = "/xmlsvr.asp";
        private static HttpClient httpClient;

        public SMSProviderType ProviderType => SMSProviderType.ASPSMS;

        public TwoFactorAuthenticationType TwoFactorAuthenticationType => TwoFactorAuthenticationType.SMS;

        public string UserKey { get; set; }
        public string Password { get; set; }
        
        public ASPSMSProvider(string userKey, string password)
        {
            UserKey = userKey;
            Password = password;
        }

        static ASPSMSProvider()
        {
            httpClient = new HttpClient();
        }

        private Dictionary<string, string> ReadASPResponse(HttpResponseMessage response)
        {
            var xmlReader = XmlReader.Create(response.Content.ReadAsStream());

            var results = new Dictionary<string, string>();
            if (xmlReader.ReadToFollowing("aspsms"))
            {
                if (!xmlReader.Read())
                {
                    return results;
                }
                while (true)
                {
                    switch (xmlReader.NodeType)
                    {
                        case XmlNodeType.Element:
                            var name = xmlReader.Name;
                            if(name == "DeliveryNotification")
                            {
                                xmlReader.Skip();
                            }
                            else
                            {
                                results[xmlReader.Name] = xmlReader.ReadElementContentAsString();
                            }
                            break;
                        default:
                            if (!xmlReader.Read())
                            {
                                return results;
                            }
                            break;
                    }
                }
            }
            return results;
        }

        public bool SendMessage(string recipient, string message)
        {
            try
            {
                var outputStream = new MemoryStream();

                var xmlTextWriter = XmlWriter.Create(outputStream);
                xmlTextWriter.WriteStartDocument();
                xmlTextWriter.WriteStartElement("aspsms");

                xmlTextWriter.WriteStartElement("Userkey");
                xmlTextWriter.WriteString(UserKey);
                xmlTextWriter.WriteEndElement();

                xmlTextWriter.WriteStartElement("Password");
                xmlTextWriter.WriteString(Password);
                xmlTextWriter.WriteEndElement();

                xmlTextWriter.WriteStartElement("Recipient");
                xmlTextWriter.WriteStartElement("PhoneNumber");
                xmlTextWriter.WriteString(recipient);
                xmlTextWriter.WriteEndElement();
                xmlTextWriter.WriteEndElement();

                xmlTextWriter.WriteStartElement("MessageData");
                xmlTextWriter.WriteString(message);
                xmlTextWriter.WriteEndElement();

                xmlTextWriter.WriteStartElement("Action");
                xmlTextWriter.WriteString("SendTextSMS");
                xmlTextWriter.WriteEndElement();

                xmlTextWriter.WriteEndElement();
                xmlTextWriter.WriteEndDocument();
                xmlTextWriter.Flush();

                outputStream.Position = 0;

                var content = new StreamContent(outputStream);

                var task = httpClient.PostAsync($"http://{aspHost}:{aspPort}{aspUrl}", content);
                task.Wait();
                var results = ReadASPResponse(task.Result);

                var errorCode = results.GetValueOrDefault("ErrorCode") ?? "1";
                if(errorCode != "1")
                {
                    Logger.Send(LogType.Information, "", $"Error while sending SMS code: {results.GetValueOrDefault("ErrorDescription", "Unknown Error")}");
                    return false;
                }

                return true;
            }
            catch(Exception e)
            {
                Logger.Send(LogType.Information, "", $"Error while sending SMS code: {CoreUtils.FormatException(e)}");
                return false;
            }
        }
    }
}
