using EVCB_OCPP.Domain;
using EVCB_OCPP.Domain.Models.Database;
using EVCB_OCPP.Packet.Messages.SubTypes;
using EVCB_OCPP.WSServer.Dto;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using System;
using System.Collections.Generic;
using System.Linq;
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;
        private readonly IDbContextFactory<MainDBContext> maindbContextFactory;

        public string CustomerId
        {
            get => _CustomerId;
            set
            {
                _CustomerId = value;
                signMaterial = GetSign(_CustomerId).Result;
            }
        }

        public OuterBusinessService(IDbContextFactory<MainDBContext> maindbContextFactory)
        {
            this.maindbContextFactory = maindbContextFactory;
        }


        async public Task<IdTokenInfo> Authorize(string chargeBoxId, string idTag)
        {
            await Task.Delay(10);
            IdTokenInfo result = new IdTokenInfo() { IdTagInfo = new IdTagInfo() { status = AuthorizationStatus.Invalid } };

            try
            {
                string requestParams = string.Format("charging_auth?ChargeBoxId={0}&IdTag={1}", chargeBoxId, idTag);

               // if (CustomerId.ToLower() == "9e6bfdcc-09fb-4dab-a428-43fe507600a3")
                {
                    logger.Info(chargeBoxId + " Charging Monitor======================================>");
                    logger.Info(signMaterial.APIUrl + requestParams);
                }
                var response = await httpClient.Post(signMaterial.APIUrl + requestParams, new Dictionary<string, string>()
                            {
                                { "PartnerId",signMaterial.Id}

                            }, null, signMaterial.SaltKey).ConfigureAwait(false);
               // if (CustomerId.ToLower() == "9e6bfdcc-09fb-4dab-a428-43fe507600a3")
                {
                    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 async Task<CustomerSignMaterial> GetSign(string customerId)
        {
            Guid Id = new Guid(customerId);
            CustomerSignMaterial _customer = new CustomerSignMaterial();


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

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