using EvaPOS_API_FRAME.DTO.Intercambio;
using EvaPOS_API_FRAME.DTO;
using EvaPOS_API_FRAME.RespuestasXML;
using EvaPosSrvDTO;
using EvaPosSrvResp;
using Serilog;
using System.Globalization;
using RestSharp;
using gatewayGK.POSGk;
using System.Text.Json;
using Newtonsoft.Json.Linq;
using GatewaySCO;
using Newtonsoft.Json;
using IO.Swagger.Model;

namespace gatewayGK.ComandosGk
{
    ///<summary>
    /// Calcular el impuesto de un item.
    /// TODO - terminar esto.
    /// </summary>
    public class CalculateTaxtCmdGk : IComando
    {
        public string Referencia { get; set; } = "scsns:AddItem";
        /// <summary>
        /// DTO con solicitud.
        /// </summary>
        public AddItemRequestDTO Request { get; private set; }

        /// <summary>
        /// Url servicio autenticación Gk.
        /// </summary>
        private string _urlRegisterItem = Entorno<EntornoGK>.Instancia.get().UrlBase
            + "services/com.gk_software.pos.api.service.taxengine.TaxEngineService/calculateTax";

        /// <summary>
        /// Calcular impuestos.
        /// </summary>
        public Respuestas Ejecutar()
        {
            Log.Debug("Cmd CalculateTaxtCmdGk ejecutado. AddItemRequest : {AddItemRequest}", Request.RequestID);



            //int requestIdGuardado = RequestIdGuardado();
            POSBCStatusEvent posbcStatus = null;
            TransactionStatusEvent transactionStatusEvent = null;
            POSReceiptEventHeaderResponse posReceiptEventHeader = null;
            POSReceiptEvent pOSReceiptEvent = null;
            TotalsEventResponse totalEvent = null;

            // Parámetros de invocación servicios web: TaxEngineServiceCalculateTaxAsync
            // Var definición de esta clase para sus parámetros requeridos de inicialización.
            ComGkSoftwareGkrApiTxpoolDtoTransaction dtoTransactionCalculateTax = new()
            {
                Key = new()
                {
                    BusinessUnitGroupID = Entorno<EntornoGK>.Instancia.get().BusinessUnitGroupID,
                    TransactionID = ""
                },
                OperatorID = "",
                WorkstationID = "",
                BusinessUnitID = "",
                BusinessDayDate = "",
                SequenceNumber = 0,
                TransactionTypeCode = "",
                InternalSequenceNumber = 0,
                FiscalFlag = true,
                IsocurrencyCode = ""
            };




            //Variables para manejar las respuestas de error - (item con peso, no se encuentra el item,item requiere cantidad)

            Respuestas respuesta = null;


            //Variables del adaptador de entrada - addItem
            int requestId = Request.RequestID;


            // --- cliente rest.
            var options = new RestClientOptions()
            {
                // TODO manejar el timeout como un parámetro de configuración.
                MaxTimeout = -1,
                RemoteCertificateValidationCallback = (sender, certificate, chain, sslPolicyErrors) => true
            };
            string sessionId = Entorno<EntornoGK>.Instancia.get().posSessionId;
            string cookieValue = $"sessionid={sessionId}";

            var client = new RestClient(options);
            var request = new RestRequest(_urlRegisterItem, Method.Post);
            request.AddHeader("Accept", "application/json;Format=GK-PLAIN-JSON");
            request.AddHeader("Content-Type", "application/json;Format=GK-PLAIN-JSON");
            request.AddHeader("_pos_session_", sessionId);
            request.AddHeader("Cookie", cookieValue);

            // Record inicializado por nombre de propiedades.
            dtoTransactionCalculateTax = new ComGkSoftwareGkrApiTxpoolDtoTransaction();
            var key = new Key();

            // TODO - usar newtonsoft
            string json = System.Text.Json.JsonSerializer.Serialize(dtoTransactionCalculateTax);
            request.AddJsonBody(json);
            Log.Verbose(">> GK registerLineItem - sessionId {sessionId}", sessionId);
            Log.Verbose(">> GK registerLineItem - body {body}", json);
            Log.Information(">> GK calculateTax");

            RestResponse response = client.Execute(request);
            System.Net.HttpStatusCode statusCode = response.StatusCode;
            int numericStatusCode = (int)statusCode;
            Log.Information("<< GK registerLineItem - Http.StatusCode {StatusCode}, Http.numericStatusCode {numericStatusCode}", response.StatusCode, numericStatusCode);
            Log.Verbose("<< GK registerLineItem - Headers {Headers}", response.Headers);
            Log.Verbose("<< GK registerLineItem - Content {Content}", response.Content);

            if (response.IsSuccessful == false)
            {
                if (response.StatusCode == System.Net.HttpStatusCode.InternalServerError)
                {
                    var jsonRespErr = System.Text.Json.JsonSerializer.Deserialize<JsonElement>(response.Content
                        ?? throw new ApplicationException("Null content in response to POST method."));

                    var errorCode = jsonRespErr.GetProperty("errorCode").GetProperty("errorCode").GetString();
                    var message = jsonRespErr.GetProperty("errorCode").GetProperty("message").GetString();
                    var posItemID = jsonRespErr.GetProperty("additionalContextInfoMap").GetProperty("posItemID").GetString();
                    Log.Warning("<< GK registerLineItem - errorCode {errorCode}, message {message}, posItemID {posItemID}",
                            errorCode, message, posItemID);
                }
                // TODO - interpretar la respuesta par amostrar el mensaje de error, ejemplo:
                // {"errorCode":{"errorCode":"GKR-POS-000001","message":"Invalid session","messageKey":"com.gk_software.pos.utils.error.ErrorCodeMessages.MSG_INVALID_SESSION","arguments":[]},"timestamp":"2023-08-04T07:16:57.066","additionalContextInfoMap":{}}
                Log.Error("<< GK registerLineItem failed: StatusCode {StatusCode}, Content {Content}",
                    response.StatusCode, response.Content);
                throw new ApplicationException("Servicio POST 'registerLineItem' en error.");
            }

            // En este punto, la respuesta es exitosa a nivel de http.

            var respTransacAddItem = Newtonsoft.Json.JsonConvert.DeserializeObject<ComGkSoftwarePosApiServiceTransactionRegistrationResult>(
                    response.Content ?? throw new ApplicationException("Null content in response to POST method."))
                    ?? throw new ApplicationException("Null content in response to POST method.");
            // Log.Verbose("<< GK registerLineItem: respNewtonsoft {respNewtonsoft}", respTransacAddItem);

            // La respuesta puede ser IsSuccessful == true pero aún así se debe validar si hay  
            // mas conediciones de falla o alertas asociadas al atrículo.
            if (respTransacAddItem.StatusOk == false)
            {
                Log.Warning("<< GK registerLineItem - statusOk {statusOk}", respTransacAddItem.StatusOk);

                // TODO : esto no corresonde a mensaje a CHEC apropiado.
                respuesta = new Respuestas { new AddItemResponseError(1,
                        TipoMensaje.Resp, requestId, "Error no reconocido", "ITEM_NOT_FOUND") };
                return respuesta;
            }

            // En este punto statusOk == True : el item ingreso a la transacción de venta.
            var transactionId = respTransacAddItem.PrimaryEntry.Transaction.Key.TransactionID;
            var businessUnitGroupID = respTransacAddItem.PrimaryEntry.Transaction.Key.BusinessUnitGroupID;
            var addedOrModifiedLineItems = respTransacAddItem.PrimaryEntry.AddedOrModifiedLineItems[0].SaleReturnLineItemList[0];
            var itemId = addedOrModifiedLineItems.ItemID;
            var regularUnitPrice = addedOrModifiedLineItems.RegularUnitPrice;
            var quantityService = addedOrModifiedLineItems.Quantity;
            var units = addedOrModifiedLineItems.Units;
            var receiptText = addedOrModifiedLineItems.ReceiptText;
            var registrationNumber = addedOrModifiedLineItems.RegistrationNumber;
            var extensionSequenceNumber = addedOrModifiedLineItems.SaleReturnLineItemExtensionList[0].Key.ExtensionSequenceNumber;
            var retailTransactionList = respTransacAddItem.PrimaryEntry.Transaction.RetailTransactionList;
            var dtoRetailTransactionTotalList = retailTransactionList[0].RetailTransactionTotalList;

            double? total = 0.0;
            double? subtotal = 0.0;
            double? subtotalDcto = 0.0;

            //Pasarlo a string
            var regularUnitPriceTrans = regularUnitPrice.ToString();

            Log.Debug("<< GK TransactionRegistrationResult: transactionId {transactionId}, itemId {itemId}, regularUnitPrice {regularUnitPrice}, quantityService {quantityService}, units {units}, textName {textName}",
                      transactionId,
                      itemId,
                      regularUnitPrice,
                      quantityService,
                      units,
                      receiptText
                      );
            Log.Information(String.Format("{0,3} | {1,13} | {2,-20} | {3,3}| {4,-5:N2} | {5,8:N2} | {6,12:N2} | {7,12:N2} | {8,12:N2} | {9,3}",
                addedOrModifiedLineItems.Key.RetailTransactionLineItemSequenceNumber,
                registrationNumber,
                receiptText,
                addedOrModifiedLineItems.UnitOfMeasureCode,
                addedOrModifiedLineItems.Quantity,
                addedOrModifiedLineItems.ActualUnitPrice,
                addedOrModifiedLineItems.ExtendedAmount,
                addedOrModifiedLineItems.ExtendedDiscountAmount,
                addedOrModifiedLineItems.GrandExtendedAmount,
                addedOrModifiedLineItems.TaxGroupID
            ));
            Log.Information(String.Format("SUBTOTAL: {0,12:N2} // SUBTOTAL_DISCOUNT: {1,12:N2} // TOTAL: {2,12:N2}",
                subtotal, subtotalDcto, total));
            Entorno<EntornoGK>.Instancia.get().TransactionID = transactionId;

            string tomarNombreCorto = "";
            //Valores que se mandan en chec
            var date = DateTime.Now.ToString("dd/MM/yyyy");
            CultureInfo culture = new CultureInfo("en-US");
            culture.DateTimeFormat.AMDesignator = "AM";
            culture.DateTimeFormat.PMDesignator = "PM";
            var time = DateTime.Now.ToString("hh:mm tt", culture);

            transactionStatusEvent = new TransactionStatusEvent(1, TipoMensaje.Event, requestId, "TRANSACTION_START", 1, "regularSale", "sales", date, time);
            pOSReceiptEvent = new POSReceiptEvent(1, TipoMensaje.Event, requestId, "Customer", 0, "Body", requestId, 1, "center", "LineItem", "ItemSale", itemId + "   " + receiptText + "      " + quantityService + "      " + regularUnitPrice, "Add");
            posReceiptEventHeader = new POSReceiptEventHeaderResponse(1, TipoMensaje.Event, requestId);
            totalEvent = new TotalsEventResponse(1, TipoMensaje.Event, requestId, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, regularUnitPriceTrans, "0.00", "0.00", "0.00", "0.00", "0.00", 1, 0, "0.00", "0.00");
            respuesta = new Respuestas { transactionStatusEvent, posReceiptEventHeader, pOSReceiptEvent, totalEvent };

            return respuesta;
        }
        public IComando CreaCopia()
        {
            return (AddItemRequestCmdGk)this.MemberwiseClone();
        }

        public void CargaDTO(DTOBase addItemRequestDTO)
        {
            Request = (AddItemRequestDTO)addItemRequestDTO;
        }
    }
}
