using EVCB_OCPP.Domain;
using EVCB_OCPP.Domain.Models.Database;
using EVCB_OCPP.Packet.Messages.SubTypes;
using EVCB_OCPP.WSServer.Dto;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;

namespace EVCB_OCPP.WSServer.Service
{
    internal class CPOOuterResponse
    {
        public CPOOuterResponse()
        {
            StatusCode = 0;

        }

        public int StatusCode { set; get; }

        public string StatusMessage { set; get; }

        public string Data { set; get; }

        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string SerialNo { set; get; }


        [JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
        public string ErrorDetail { set; get; }


    }
    internal class CustomerSignMaterial
    {
        internal bool CallsThirdParty { set; get; }

        internal string Id { set; get; }

        internal string APIUrl { set; get; }

        internal string SaltKey { set; get; }
    }
    public class OuterBusinessService : IBusinessService
    {
        static private ILogger logger = NLog.LogManager.GetCurrentClassLogger();
        private OuterHttpClient httpClient = new OuterHttpClient();
        private CustomerSignMaterial signMaterial = null;
        private string CustomerId = string.Empty;
        public OuterBusinessService(string customerId)
        {
            CustomerId = customerId;
            signMaterial = GetSign(customerId);
        }


        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag,int? connectorId =-1)
        {
            await Task.Delay(10);
            IdTokenInfo result = new IdTokenInfo() { IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Invalid } };
            bool normaalAuth = true;
        
            try
            {
                #region PnC
                if (idTag.StartsWith("vid:"))
                {

                    idTag = idTag.Replace("vid:","");
                    normaalAuth = false;
                    if(connectorId==-1)
                    {
                        using (var db = new MainDBContext())
                        {
                            var connectorStatuses = db.ConnectorStatus.Where(x => x.ChargeBoxId == chargeBoxId).
                                 Select(x => new { x.ConnectorId, x.Status, x.CreatedOn }).ToList();

                            var connectorStatus = connectorStatuses.Where(x => x.Status == 2).OrderByDescending(x => x.CreatedOn).FirstOrDefault();
                            if (connectorStatus != null) { connectorId = connectorStatus.ConnectorId; }

                        }
                    }
                   
                }
                #endregion

                string requestParams = normaalAuth ? string.Format("charging_auth?ChargeBoxId={0}&IdTag={1}", chargeBoxId, idTag) :
                    string.Format("charging_auth?ChargeBoxId={0}&ConnectorId={1}&IdTag={2}", chargeBoxId, connectorId, idTag);

                var response = await httpClient.Post(signMaterial.APIUrl + requestParams, new Dictionary<string, string>()
                            {
                                { "PartnerId",signMaterial.Id}

                            }, null, signMaterial.SaltKey).ConfigureAwait(false);

                logger.Info(chargeBoxId + " Charging Monitor======================================>");
                logger.Info(signMaterial.APIUrl + requestParams);
                logger.Info(JsonConvert.SerializeObject(response));
                if (response.Success)
                {
                    Console.WriteLine(response.Response);
                    var _httpResult = JsonConvert.DeserializeObject<CPOOuterResponse>(response.Response);
                    JObject jo = JObject.Parse(_httpResult.Data);

                    if (jo.ContainsKey("ExpiryDate"))
                    {
                        DateTime dt = jo["ExpiryDate"].Value<DateTime>();
                        result.IdTagInfo.expiryDate = dt;
                    }

                    if (jo.ContainsKey("ParentIdTag"))
                    {
                        string _Message = jo["ParentIdTag"].Value<string>();
                        result.IdTagInfo.parentIdTag = _Message;

                    }

                    if (jo.ContainsKey("ChargePointFee"))
                    {


                        for (int i = 0; i < jo["ChargePointFee"].Count(); i++)
                        {
                            if (i == 0)
                            {
                                result.ChargePointFee = new List<ChargePointFee>();
                            }
                            result.ChargePointFee.Add(jo["ChargePointFee"][i].ToObject<ChargePointFee>());
                        }

                    }

                    if (jo.ContainsKey("ChargepointFee"))
                    {

                        for (int i = 0; i < jo["ChargepointFee"].Count(); i++)
                        {
                            if (i == 0)
                            {
                                result.ChargePointFee = new List<ChargePointFee>();
                            }

                            result.ChargePointFee.Add(jo["ChargepointFee"][i].ToObject<ChargePointFee>());
                        }

                    }

                    if (jo.ContainsKey("AccountBalance"))
                    {
                        decimal accountBalance = jo["AccountBalance"].Value<decimal>();
                        result.AccountBalance = accountBalance;
                    }


                    if (jo.ContainsKey("Status"))
                    {
                        string _Message = jo["Status"].Value<string>();
                        result.IdTagInfo.status = (AuthorizationStatus)Enum.Parse(typeof(AuthorizationStatus), _Message);
                    }
                }
                else
                {
                    logger.Error(chargeBoxId + " OuterBusinessService.Authorize Fail: " + response.Response);
                }

            }
            catch (Exception ex)
            {
                result.IdTagInfo.status = AuthorizationStatus.Invalid;

                logger.Error(chargeBoxId + " OuterBusinessService.Authorize Ex: " + ex.ToString());
            }

            return result;

        }

        async public Task NotifyFaultStatus(ErrorDetails details)
        {

            try
            {
                if (signMaterial.CallsThirdParty)
                {




                    var response = await httpClient.Post(signMaterial.APIUrl + "connectorfault", new Dictionary<string, string>()
                            {
                                { "PartnerId",signMaterial.Id}

                            }, details, signMaterial.SaltKey).ConfigureAwait(false);



                }


            }
            catch (Exception ex)
            {

                logger.Error(details.ChargeBoxId + " OuterBusinessService.NotifyFaultStatus Ex: " + ex.ToString());
            }


        }

        async public Task NotifyConnectorUnplugged(string chargeBoxId, string data)
        {
            try
            {
                JObject jo = JObject.Parse(data);

                var details = new { ChargeBoxId = chargeBoxId, SessionId = jo["idTx"].Value<Int32>(), Timestamp = jo["timestamp"].Value<DateTime>() };
                if (signMaterial.CallsThirdParty)
                {
                    var response = await httpClient.Post(signMaterial.APIUrl + "connectorunplugged", new Dictionary<string, string>()
                            {
                                { "PartnerId",signMaterial.Id}

                            }, details, signMaterial.SaltKey).ConfigureAwait(false);


                }


            }
            catch (Exception ex)
            {

                logger.Error(chargeBoxId + " OuterBusinessService.NotifyConnectorUnplugged Ex: " + ex.ToString());
            }

        }

        private CustomerSignMaterial GetSign(string customerId)
        {
            Guid Id = new Guid(customerId);
            CustomerSignMaterial _customer = new CustomerSignMaterial();


            using (var db = new MainDBContext())
            {
                _customer = db.Customer.Where(x => x.Id == Id).Select(x => new CustomerSignMaterial() { Id = x.Id.ToString(), APIUrl = x.ApiUrl, SaltKey = x.ApiKey, CallsThirdParty = x.CallPartnerApiOnSchedule }).FirstOrDefault();
            }
            return _customer;
        }

        public Task NotifyConnectorUnplugged(string data)
        {
            throw new NotImplementedException();
        }
    }
}
