using EVCB_OCPP.Packet.Features;
using EVCB_OCPP.Packet.Messages;
using EVCB_OCPP.WSServer.Service.WsService;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using NLog;


namespace EVCB_OCPP.WSServer.Message
{
    /// <summary>
    /// 實現 OCPP 基本傳送規範,
    /// 1.訊息 基本格式,將訊息包裝成 Call 、CallResult、CallError 三種格式
    /// 2.OCPP 定義的傳送規則:交易相關的訊息必須依照時序性傳送,一個傳完才能接著送下一個(忽略規則 由Center System定義)
    /// </summary>
    internal class BasicMessageHandler
    {
        static internal Logger logger = NLog.LogManager.GetCurrentClassLogger();

        #region 傳送 or 解析訊息需要欄位
        private const int INDEX_MESSAGEID = 0;
        private const int INDEX_UNIQUEID = 1;
        internal const int TYPENUMBER_CALL = 2;
        private const int INDEX_CALL_ACTION = 2;
        private const int INDEX_CALL_PAYLOAD = 3;

        internal const int TYPENUMBER_CALLRESULT = 3;
        private const int INDEX_CALLRESULT_PAYLOAD = 2;

        internal const int TYPENUMBER_CALLERROR = 4;
        private const int INDEX_CALLERROR_ERRORCODE = 2;
        private const int INDEX_CALLERROR_DESCRIPTION = 3;
        private const int INDEX_CALLERROR_PAYLOAD = 4;

        private const string CALL_FORMAT = "[2,\"{0}\",\"{1}\",{2}]";
        private const string CALLRESULT_FORMAT = "[3,\"{0}\",{1}]";
        private const string CALLERROR_FORMAT = "[4,\"{0}\",\"{1}\",\"{2}\",{3}]";
        private const string DATE_FORMAT = "yyyy-MM-dd'T'HH:mm:ss'Z'";
        private const string DATE_FORMAT_WITH_MS = "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'";
        #endregion

        private OCPP16MessageHandler _ocpp16Handler = new OCPP16MessageHandler();
        private OCPP20MessageHandler _ocpp20Handler = new OCPP20MessageHandler();

        /// <summary>
        /// 將收到的封包做基本的拆解分成 Call 、CallResult、CallError
        /// </summary>
        /// <param name="client"></param>
        /// <param name="data"></param>
        /// <returns></returns>
        internal MessageResult AnalysisReceiveData(WsClientData client, string data)
        {
            MessageResult result = null;
            if (!client.ISOCPP20)
            {
                result = _ocpp16Handler.AnalysisReceiveData(client, data);
            }
            else
            {
                result = _ocpp20Handler.AnalysisReceiveData(client, data);
            }

            return result;
        }


        static internal string GenerateCallError(string uniqueId, string errorCode, string errorDescription)
        {

            string msg = string.Format(CALLERROR_FORMAT, uniqueId, errorCode, errorDescription, "{}");
            return msg;

        }

        static internal string GenerateConfirmation(string uniqueId, IConfirmation confirmation)
        {
            string msg = string.Empty;
            if (confirmation != null && confirmation.Validate())
            {

                msg = string.Format(CALLRESULT_FORMAT, uniqueId, JsonConvert.SerializeObject(confirmation, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
            }
            else
            {
                logger.Error(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
            }
            return msg;
        }
        static internal string GenerateConfirmationofOCPP20(string uniqueId, EVCB_OCPP20.Packet.Messages.IConfirmation confirmation)
        {
            string msg = string.Empty;
            if (confirmation != null && confirmation.Validate())
            {

                msg = string.Format(CALLRESULT_FORMAT, uniqueId, JsonConvert.SerializeObject(confirmation, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
            }
            else
            {
                logger.Error(string.Format("confirmation is null  or InVaild in GenerateConfirmation Method"), "Warning");
            }
            return msg;
        }

        static internal string GenerateRequest(string uniqueId, string action, IRequest request)
        {
            string msg = string.Empty;
            if (request != null && request.Validate())
            {

                msg = string.Format(CALL_FORMAT, uniqueId, action, JsonConvert.SerializeObject(request, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
            }
            else
            {
                if (action == Actions.ChangeConfiguration.ToString())
                {
                    if(!request.Validate())
                    {
                        logger.Error("!Validate", "Warning");
                    }

                    if (request == null)
                    {
                        logger.Error("!NULL", "Warning");
                    }

                }

                logger.Error(string.Format("confirmation is null  or InVaild in GenerateRequest Method "+ action), "Warning");
            }
            return msg;
        }

        static internal string GenerateRequestofOCPP20(string uniqueId, string action, EVCB_OCPP20.Packet.Messages.IRequest request)
        {
            string msg = string.Empty;
            if (request != null && request.Validate())
            {

                msg = string.Format(CALL_FORMAT, uniqueId, action, JsonConvert.SerializeObject(request, new JsonSerializerSettings() { ContractResolver = new CamelCasePropertyNamesContractResolver(), NullValueHandling = NullValueHandling.Ignore, Formatting = Formatting.None }));
            }
            else
            {
                logger.Error(string.Format("confirmation is null  or InVaild in GenerateRequest Method"), "Warning");
            }
            return msg;
        }

        static internal string GenerateDestroyRequest(string uniqueId, string action, string request)
        {


            return string.Format(CALL_FORMAT, uniqueId, action, request);
        }
    }
}