using System;
using Partner;
using System.Net;
using System.Linq;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System.Configuration;
using FedexOnlineServiceHelper;
using System.Collections.Generic;
using System.Threading.Tasks;
using System.Xml;

/// <summary>
/// Summary description for CommonService
/// </summary>
public class CommonService
{
    #region Declaration
    private static string appMode = ConfigurationManager.AppSettings[Constant.appMode];
    private static string sfUserName = ConfigurationManager.AppSettings[Constant.sfUserName];
    private static string sfPassword = ConfigurationManager.AppSettings[Constant.sfPassword];
    private static string patnerUrlWSDL = ConfigurationManager.AppSettings[Constant.wsdlUrl];

    private SforceService binding;
    #endregion

    public CommonService()
    {
        // constructor logic here
    }

    #region Salesforce
    public SforceService SalesforceConnect()
    {
        try
        {
            LoginResult lr = new LoginResult();
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
            binding = new SforceService();

            if (appMode == "Production")
            {
                binding.Url = patnerUrlWSDL;
            }

            lr = binding.login(Convert.ToString(sfUserName), Convert.ToString(sfPassword));
            binding.Url = lr.serverUrl;
            binding.SessionHeaderValue = new SessionHeader { sessionId = lr.sessionId };
        }
        catch (Exception ex)
        {
            Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "SalesforceConnect", ex.Message + " \n " + Constant.STACKTRACE + ex.StackTrace);
        }
        return binding;
    }
    #endregion

    #region FedEx 
    public FedexHelper BuildFedexHelper(JObject jObject, ref string fedexErrorMessage)
    {
        FedexHelper objFedexHelper = new FedexHelper();
        try
        {
            if (jObject["Any"] != null && jObject["Any"].HasValues)
            {
                FedexHelper.Any any = new FedexHelper.Any();
                FedexHelper.RMAListsR rMAListsR = new FedexHelper.RMAListsR();

                var settings = new JsonSerializerSettings
                {                    
                    NullValueHandling = NullValueHandling.Include,
                    MissingMemberHandling = MissingMemberHandling.Ignore
                };

                var nilsettings = new JsonSerializerSettings
                {
                    Converters = { new SalesforceNilConverter() },
                    MissingMemberHandling = MissingMemberHandling.Ignore  // ignores @type, type, Id
                };

                JArray jArray = (JArray)jObject["Any"];
                foreach (JObject rma_jObject in jArray)
                {
                    string propValue = GetPropertyName(rma_jObject);
                    switch (propValue)
                    {
                        case "Name":
                            try
                            {
                                any.Name = GetJsonValue(rma_jObject["Name"]);
                                Constant.Name = GetJsonValue(rma_jObject["Name"]);
                            }
                            catch (Exception ex)
                            {
                                any.Name = string.Empty;
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Name", Convert.ToString(ex.Message));
                            }
                            break;

                        case "Contact__r":
                            try
                            {
                                string contact = GetJsonValue(rma_jObject["Contact__r"]);
                                any.Contact__r = JsonConvert.DeserializeObject<FedexHelper.ContactR>(contact, settings);
                            }
                            catch (Exception ex)
                            {
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Contact__r", Convert.ToString(ex.Message));
                            }
                            break;

                        case "Account__r":
                            try
                            {
                                string account = GetJsonValue(rma_jObject["Account__r"]);
                                JObject jObjectOfAccount = JObject.Parse(account);
                                FedexHelper.AccountR accountR = new FedexHelper.AccountR()
                                {
                                    ShippingCity = GetJsonValue(jObjectOfAccount["ShippingCity"]),
                                    ShippingState = GetJsonValue(jObjectOfAccount["ShippingState"]),
                                    ShippingStreet = GetJsonValue(jObjectOfAccount["ShippingStreet"]),
                                    ShippingPostalCode = GetJsonValue(jObjectOfAccount["ShippingPostalCode"]),
                                    ShippingCountry = (jObjectOfAccount["ShippingCountry"].GetType() == typeof(JObject)) ? string.Empty : GetJsonValue(jObjectOfAccount["ShippingCountry"])
                                };
                                any.Account__r = accountR;

                                //any.Account__r = JsonConvert.DeserializeObject<FedexHelper.AccountR>(account, settings);
                            }
                            catch (Exception ex)
                            {
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Account__r", Convert.ToString(ex.Message));
                            }
                            break;

                        case "FedexDetail__r":
                            try
                            {
                                string fedEx = GetJsonValue(rma_jObject["FedexDetail__r"]);

                                any.FedexDetail__r = JsonConvert.DeserializeObject<FedexHelper.FedexDetailR>(fedEx, nilsettings);
                            }
                            catch (Exception ex)
                            {
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - FedexDetail__r", Convert.ToString(ex.Message));
                            }
                            break;

                        case "RMA_Lists__r":
                            try
                            {
                                string valueOfList = GetJsonValue(rma_jObject["RMA_Lists__r"]);
                                JObject jObjectOfToken = JObject.Parse(valueOfList);

                                string size = GetJsonValue(jObjectOfToken["size"]);
                                if (!string.IsNullOrEmpty(size))
                                {
                                    rMAListsR.size = Convert.ToInt32(size);
                                }

                                if (jObjectOfToken != null && jObjectOfToken["records"].GetType() == typeof(JObject))
                                {
                                    FedexHelper.Records record = new FedexHelper.Records();

                                    string valueOfRecord = GetJsonValue(jObjectOfToken["records"]);
                                    JObject jObjectOfRecords = JObject.Parse(valueOfRecord);

                                    if (jObjectOfRecords != null && jObjectOfRecords["Serial_Number__c"].GetType() == typeof(JObject))
                                    {
                                        record.Serial_Number__c = string.Empty;
                                    }
                                    else
                                    {
                                        record.Serial_Number__c = Convert.ToString(GetJsonValue(jObjectOfRecords["Serial_Number__c"]));
                                    }
                                    record.RMANumber__c = Convert.ToString(GetJsonValue(jObjectOfRecords["RMANumber__c"]));
                                    record.CreatedDate = Convert.ToDateTime(GetJsonValue(jObjectOfRecords["CreatedDate"]));
                                    record.ProductCode__r = JsonConvert.DeserializeObject<FedexHelper.ProductCodeR>(Convert.ToString(jObjectOfRecords["ProductCode__r"]), settings);
                                    rMAListsR.records.Add(record);
                                }

                                if (jObjectOfToken != null && jObjectOfToken["records"].GetType() == typeof(JArray))
                                {
                                    string valueOfRecord = GetJsonValue(jObjectOfToken["records"]);
                                    JArray jArrayOfRecords = JArray.Parse(valueOfRecord);

                                    if (jArrayOfRecords != null && jArrayOfRecords.Count > 0)
                                    {
                                        foreach (var recordItem in jArrayOfRecords)
                                        {
                                            FedexHelper.Records record = new FedexHelper.Records();
                                            if (recordItem != null && recordItem["Serial_Number__c"].GetType() == typeof(JObject))
                                            {
                                                record.Serial_Number__c = string.Empty;
                                            }
                                            else
                                            {
                                                record.Serial_Number__c = Convert.ToString(GetJsonValue(recordItem["Serial_Number__c"]));
                                            }
                                            record.RMANumber__c = Convert.ToString(GetJsonValue(recordItem["RMANumber__c"]));
                                            record.CreatedDate = Convert.ToDateTime(GetJsonValue(recordItem["CreatedDate"]));
                                            record.ProductCode__r = JsonConvert.DeserializeObject<FedexHelper.ProductCodeR>(Convert.ToString(recordItem["ProductCode__r"]), settings);
                                            rMAListsR.records.Add(record);
                                        }
                                        rMAListsR.records = rMAListsR.records.OrderBy(x => x.CreatedDate).ToList();
                                    }
                                }
                            }
                            catch (Exception ex)
                            {
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - RMA_Lists__r", Convert.ToString(ex.Message));
                            }
                            break;

                        case "Is_Label_Generated__c":
                            try
                            {
                                any.Is_Label_Generated__c = Convert.ToBoolean(GetJsonValue(rma_jObject["Is_Label_Generated__c"]));
                            }
                            catch (Exception ex)
                            {
                                any.Is_Label_Generated__c = false;
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Is_Label_Generated__c", Convert.ToString(ex.Message));
                            }
                            break;

                        case "Fedex_TriggerPoint__c":
                            try
                            {
                                any.Fedex_TriggerPoint__c = Convert.ToBoolean(GetJsonValue(rma_jObject["Fedex_TriggerPoint__c"]));
                            }
                            catch (Exception ex)
                            {
                                any.Fedex_TriggerPoint__c = false;
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Fedex_TriggerPoint__c", Convert.ToString(ex.Message));
                            }
                            break;

                        case "Item__c":
                            try
                            {
                                decimal itemCount = Convert.ToDecimal(GetJsonValue(rma_jObject["Item__c"]));
                                any.Item__c = Convert.ToInt32(itemCount);
                            }
                            catch (Exception ex)
                            {
                                any.Item__c = 0;
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Item__c", Convert.ToString(ex.Message));
                            }
                            break;

                        case "Customer_Reference__c":
                            try
                            {
                                if (rma_jObject != null && rma_jObject["Customer_Reference__c"].GetType() == typeof(JObject))
                                {
                                    any.Customer_Reference__c = string.Empty;
                                }
                                else
                                {
                                    any.Customer_Reference__c = GetJsonValue(rma_jObject["Customer_Reference__c"]);
                                }
                            }
                            catch (Exception ex)
                            {
                                any.Customer_Reference__c = string.Empty;
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexHelper - Customer_Reference__c", Convert.ToString(ex.Message));
                            }
                        break;

                        case "FedexDetail__c":
                            try
                            {
                                any.FedexDetail__c = GetJsonValue(rma_jObject["FedexDetail__c"]);

                                // ALSO MAP INTO OBJECT (VERY IMPORTANT)
                                if (any.FedexDetail__r == null)
                                    any.FedexDetail__r = new FedexHelper.FedexDetailR();

                                any.FedexDetail__r.FedexDetail__c = any.FedexDetail__c;
                            }
                            catch (Exception ex)
                            {
                                Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id,
                                    "BuildFedexHelper - FedexDetail__c", Convert.ToString(ex.Message));
                            }
                        break;
                    }
                }

                objFedexHelper.Id = Constant.Id;
                objFedexHelper.any = any;
                objFedexHelper.any.RMA_Lists__r = rMAListsR;
            }
        }
        catch (Exception ex)
        {
            fedexErrorMessage = ex.Message;
            Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "BuildFedexModel", ex.Message + " \n " + ex.StackTrace);
        }
        return objFedexHelper;
    }

    public bool GenerateFedexModel(FedexHelper fedexHelper, ref List<string> lstOfError, ref List<string> lstOfFile)
    {
        try
        {
            FedexOnlineService fedexOnlineService = new FedexOnlineService();

            // STEP 1: Generate token ONCE
            var fedexTokenService = new FedexTokenService();

            var tokenResult = fedexTokenService
                .GetValidToken(fedexHelper)
                .Result;

            var accessToken = tokenResult.AccessToken;

            if (string.IsNullOrEmpty(accessToken))
            {
                lstOfError.Add("FedEx token generation failed");
                return false;
            }

            // ✅ Only update Salesforce if token changed
            if (tokenResult.IsNewToken)
            {
                UpdateFedexTokenDetails(fedexHelper);
            }


            //Step 2
            int recordCount = 0;

            if (fedexHelper.any.RMA_Lists__r.records != null && fedexHelper.any.RMA_Lists__r.records.Count > 0)
            {
                foreach (var itemRecord in fedexHelper.any.RMA_Lists__r.records)
                {
                    if (fedexHelper.any.Item__c != 0 && recordCount < fedexHelper.any.Item__c)
                    {
                        FedexOnlineItemsModel fedexOnlineItems = new FedexOnlineItemsModel();
                        PackageDetails packageDetails = new PackageDetails();

                        if (fedexHelper.any != null && fedexHelper.any.FedexDetail__r != null && fedexHelper.any.Contact__r != null)
                        {
                            fedexOnlineItems.Id = !string.IsNullOrEmpty(fedexHelper.Id) ? fedexHelper.Id : Constant.Id;
                            fedexOnlineItems.Name = !string.IsNullOrEmpty(fedexHelper.any.Name) ? fedexHelper.any.Name : Constant.Name;
                            fedexOnlineItems.OrderRef = fedexOnlineItems.Id;

                            #region Application Mode
                            if (appMode == "Production")
                            {
                                fedexOnlineItems.AppMode = AppMode.PRODUCTION;
                            }
                            #endregion

                            #region FedEx Account
                            fedexOnlineItems.AccountDetails.MeterNumber = fedexHelper.any.FedexDetail__r.MeterNumber__c;
                            fedexOnlineItems.AccountDetails.AccountNumber = fedexHelper.any.FedexDetail__r.AccountNumber__c;
                            fedexOnlineItems.AccountDetails.IntegratorID = fedexHelper.any.FedexDetail__r.IntegratorID__c;
                            fedexOnlineItems.AccountDetails.ClientProductID = fedexHelper.any.FedexDetail__r.ClientProductID__c;
                            fedexOnlineItems.AccountDetails.ClientProductVersion = fedexHelper.any.FedexDetail__r.ClientProductVersion__c;
                            fedexOnlineItems.AccountDetails.UserCredentialKey = fedexHelper.any.FedexDetail__r.UserCredentialKey__c;
                            fedexOnlineItems.AccountDetails.UserCredentialPassword = fedexHelper.any.FedexDetail__r.UserCredentialPassword__c;
                            #endregion

                            #region Package Details
                            packageDetails.OrderId = itemRecord.ProductCode__r.Name;
                            packageDetails.InvoiceNumber = itemRecord.Serial_Number__c;
                            packageDetails.ReferenceNumber = fedexHelper.any.Customer_Reference__c;
                            packageDetails.WeightLb = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.WeightLb__c);
                            packageDetails.Width = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.Width__c);
                            packageDetails.Length = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.Length__c);
                            packageDetails.Height = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.Height__c);
                            fedexOnlineItems.PackageDetails.Add(packageDetails);
                            fedexOnlineItems.ShipBillWeight = fedexOnlineItems.PackageDetails.Sum(x => x.WeightLb);
                            #endregion

                            #region From Contact
                            fedexOnlineItems.From_FirstName = fedexHelper.any.Contact__r.FirstName;
                            fedexOnlineItems.From_LastName = fedexHelper.any.Contact__r.LastName;
                            fedexOnlineItems.From_Fullname = fedexOnlineItems.From_FirstName + " " + fedexOnlineItems.From_LastName;
                            fedexOnlineItems.From_Address1 = fedexHelper.any.Account__r.ShippingStreet;
                            fedexOnlineItems.From_City = fedexHelper.any.Account__r.ShippingCity;
                            fedexOnlineItems.From_Postalcode = Convert.ToString(fedexHelper.any.Account__r.ShippingPostalCode);
                            fedexOnlineItems.From_State = fedexHelper.any.Account__r.ShippingState;
                            if (!string.IsNullOrEmpty(fedexHelper.any.Account__r.ShippingCountry))
                            {
                                if (fedexHelper.any.Account__r.ShippingCountry.Contains("USA")
                                     || fedexHelper.any.Account__r.ShippingCountry.ToUpperInvariant().Equals("United States".ToUpperInvariant())
                                     || fedexHelper.any.Account__r.ShippingCountry.ToUpperInvariant().Equals("United States of America".ToUpperInvariant()))
                                {
                                    fedexOnlineItems.From_Country = Convert.ToString("US");
                                }
                                else
                                {
                                    fedexOnlineItems.From_Country = fedexHelper.any.Account__r.ShippingCountry;
                                }
                            }
                            else
                            {
                                fedexOnlineItems.From_Country = Convert.ToString("US");
                            }
                            fedexOnlineItems.From_Phone = fedexHelper.any.FedexDetail__r.ToPhoneNumber__c;
                            #endregion

                            #region To Contact
                            fedexOnlineItems.ToFirstName = fedexHelper.any.FedexDetail__r.ToFirstName__c;
                            fedexOnlineItems.ToLastName = fedexHelper.any.FedexDetail__r.ToLastName__c;
                            fedexOnlineItems.ToFullName = fedexHelper.any.FedexDetail__r.ToFullName__c;
                            fedexOnlineItems.ToAddress1 = fedexHelper.any.FedexDetail__r.ToAddress1__c;
                            fedexOnlineItems.ToCity = fedexHelper.any.FedexDetail__r.ToCity__c;
                            fedexOnlineItems.ToPostalcode = Convert.ToString(fedexHelper.any.FedexDetail__r.ToPostalcode__c);
                            fedexOnlineItems.ToState = fedexHelper.any.FedexDetail__r.ToState__c;
                            fedexOnlineItems.ToCountry = fedexHelper.any.FedexDetail__r.ToCountry__c;
                            fedexOnlineItems.ToPhoneNumber = fedexHelper.any.FedexDetail__r.ToPhoneNumber__c;
                            #endregion
                        }

                        #region FedEx Process
                        string lable = string.Empty;
                        string fedexErrorMessage = string.Empty;
                        Dictionary<string, string> fdxoXMLOutput = new Dictionary<string, string>();

                        
                        //  Call REST label service
                        var restService = new FedexLabelRestAPIService();

                        restService.GenerateLabelRest(
                            fedexOnlineItems,
                            accessToken,
                            ref fdxoXMLOutput,
                            ref fedexErrorMessage
                        );

                        //fedexOnlineService.GenerateLabel(fedexOnlineItems, ref fdxoXMLOutput, ref fedexErrorMessage);

                        #region Commented
                        //fedexOnlineService.CloseTheDay(fedexOnlineItems, ref fedexErrorMessage, ref fdxoXMLOutput);
                        //fedexOnlineService.VoidShipment(fedexOnlineItems, fedexOnlineItems.PackageDetails.Select(x => x.TrackingNumber).FirstOrDefault(), ref fedexErrorMessage, ref fdxoXMLOutput);
                        #endregion

                        if (fedexOnlineItems.ShipStatus == ShipStatus.Success)
                        {
                            lable = fedexOnlineItems.PackageDetails.FirstOrDefault().ShippinglabelPath;
                            Logger.WriteToLog(Logger.LogType.Info, Constant.FEX_TO_SF, Constant.Id, "GenerateFedexModel", "Label for item " + recordCount + " - " + lable + " " + Constant.CREATED_SUCCESSFULLY);
                            lstOfFile.Add(lable);
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(fedexErrorMessage))
                            {
                                lstOfError.Add(fedexErrorMessage);
                            }

                            Logger.WriteToLog(Logger.LogType.Error, Constant.FEX_TO_SF, Constant.Id, "GenerateFedexModel", "Error during process shipping with FedEx, " + fedexErrorMessage);

                            foreach (var item in fdxoXMLOutput)
                                Logger.WriteToLog(Logger.LogType.Info, Constant.FEX_TO_SF, Constant.Id, "GenerateFedexModel", item.Key + " : " + item.Value);
                        }
                        #endregion
                    }
                    recordCount++;
                }
            }
        }
        catch (Exception ex)
        {
            Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "GenerateFedexModel", ex.Message + " \n " + ex.StackTrace);
        }
        return true;
    }

    public bool GenerateFedexModelRate(FedexHelper fedexHelper, ref List<string> lstOfError, ref List<decimal> lstOfFile)
    {
        try
        {
            FedexRateRestAPIServices fedexRateRestAPIServices = new FedexRateRestAPIServices();
            int recordCount = 0;

            //  STEP 1: Generate token ONCE
            var fedexTokenService = new FedexTokenService();

            var tokenResult = fedexTokenService
                .GetValidToken(fedexHelper)
                .Result;

            var accessToken = tokenResult.AccessToken;

            if (string.IsNullOrEmpty(accessToken))
            {
                lstOfError.Add("FedEx token generation failed");
                return false;
            }

            // ✅ Only update Salesforce if token changed
            if (tokenResult.IsNewToken)
            {
                UpdateFedexTokenDetails(fedexHelper);
            }

            // 🔥 STEP 2: Loop records
            if (fedexHelper.any.RMA_Lists__r.records != null && fedexHelper.any.RMA_Lists__r.records.Count > 0)
            {
                foreach (var itemRecord in fedexHelper.any.RMA_Lists__r.records)
                {
                    if (fedexHelper.any.Item__c != 0 && recordCount < fedexHelper.any.Item__c)
                    {
                        FedexOnlineItemsModel fedexOnlineItems = new FedexOnlineItemsModel();
                        PackageDetails packageDetails = new PackageDetails();

                        if (fedexHelper.any != null && fedexHelper.any.FedexDetail__r != null && fedexHelper.any.Contact__r != null)
                        {
                            fedexOnlineItems.Id = !string.IsNullOrEmpty(fedexHelper.Id) ? fedexHelper.Id : Constant.Id;
                            fedexOnlineItems.Name = !string.IsNullOrEmpty(fedexHelper.any.Name) ? fedexHelper.any.Name : Constant.Name;
                            fedexOnlineItems.OrderRef = fedexOnlineItems.Id;

                            #region Application Mode
                            if (appMode == "Production")
                            {
                                fedexOnlineItems.AppMode = AppMode.PRODUCTION;
                            }
                            #endregion

                            #region FedEx Account
                            fedexOnlineItems.AccountDetails.MeterNumber = fedexHelper.any.FedexDetail__r.MeterNumber__c;
                            fedexOnlineItems.AccountDetails.AccountNumber = fedexHelper.any.FedexDetail__r.AccountNumber__c;
                            fedexOnlineItems.AccountDetails.IntegratorID = fedexHelper.any.FedexDetail__r.IntegratorID__c;
                            fedexOnlineItems.AccountDetails.ClientProductID = fedexHelper.any.FedexDetail__r.ClientProductID__c;
                            fedexOnlineItems.AccountDetails.ClientProductVersion = fedexHelper.any.FedexDetail__r.ClientProductVersion__c;
                            fedexOnlineItems.AccountDetails.UserCredentialKey = fedexHelper.any.FedexDetail__r.UserCredentialKey__c;
                            fedexOnlineItems.AccountDetails.UserCredentialPassword = fedexHelper.any.FedexDetail__r.UserCredentialPassword__c;
                            #endregion

                            #region Package Details
                            packageDetails.OrderId = itemRecord.ProductCode__r.Name;
                            packageDetails.InvoiceNumber = itemRecord.Serial_Number__c;
                            packageDetails.ReferenceNumber = fedexHelper.any.Customer_Reference__c;
                            packageDetails.WeightLb = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.WeightLb__c);
                            packageDetails.Width = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.Width__c);
                            packageDetails.Length = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.Length__c);
                            packageDetails.Height = Convert.ToDecimal(fedexHelper.any.FedexDetail__r.Height__c);

                            fedexOnlineItems.PackageDetails.Add(packageDetails);
                            fedexOnlineItems.ShipBillWeight = fedexOnlineItems.PackageDetails.Sum(x => x.WeightLb);
                            #endregion

                            #region From Contact
                            fedexOnlineItems.From_FirstName = fedexHelper.any.Contact__r.FirstName;
                            fedexOnlineItems.From_LastName = fedexHelper.any.Contact__r.LastName;
                            fedexOnlineItems.From_Fullname = fedexOnlineItems.From_FirstName + " " + fedexOnlineItems.From_LastName;
                            fedexOnlineItems.From_Address1 = fedexHelper.any.Account__r.ShippingStreet;
                            fedexOnlineItems.From_City = fedexHelper.any.Account__r.ShippingCity;
                            fedexOnlineItems.From_Postalcode = Convert.ToString(fedexHelper.any.Account__r.ShippingPostalCode);
                            fedexOnlineItems.From_State = fedexHelper.any.Account__r.ShippingState;

                            if (!string.IsNullOrEmpty(fedexHelper.any.Account__r.ShippingCountry))
                            {
                                if (fedexHelper.any.Account__r.ShippingCountry.Contains("USA")
                                    || fedexHelper.any.Account__r.ShippingCountry.ToUpperInvariant().Equals("UNITED STATES")
                                    || fedexHelper.any.Account__r.ShippingCountry.ToUpperInvariant().Equals("UNITED STATES OF AMERICA"))
                                {
                                    fedexOnlineItems.From_Country = "US";
                                }
                                else
                                {
                                    fedexOnlineItems.From_Country = fedexHelper.any.Account__r.ShippingCountry;
                                }
                            }
                            else
                            {
                                fedexOnlineItems.From_Country = "US";
                            }

                            fedexOnlineItems.From_Phone = fedexHelper.any.FedexDetail__r.ToPhoneNumber__c;
                            #endregion

                            #region To Contact
                            fedexOnlineItems.ToFirstName = fedexHelper.any.FedexDetail__r.ToFirstName__c;
                            fedexOnlineItems.ToLastName = fedexHelper.any.FedexDetail__r.ToLastName__c;
                            fedexOnlineItems.ToFullName = fedexHelper.any.FedexDetail__r.ToFullName__c;
                            fedexOnlineItems.ToAddress1 = fedexHelper.any.FedexDetail__r.ToAddress1__c;
                            fedexOnlineItems.ToCity = fedexHelper.any.FedexDetail__r.ToCity__c;
                            fedexOnlineItems.ToPostalcode = Convert.ToString(fedexHelper.any.FedexDetail__r.ToPostalcode__c);
                            fedexOnlineItems.ToState = fedexHelper.any.FedexDetail__r.ToState__c;
                            fedexOnlineItems.ToCountry = fedexHelper.any.FedexDetail__r.ToCountry__c;
                            fedexOnlineItems.ToPhoneNumber = fedexHelper.any.FedexDetail__r.ToPhoneNumber__c;
                            #endregion
                        }

                        // 🔥 RESET STATUS
                        fedexOnlineItems.ShipStatus = ShipStatus.Failed;

                        string fedexErrorMessage = string.Empty;

                        // 🔥 REST CALL
                        decimal rate = fedexRateRestAPIServices.GetRatesREST(
                            fedexOnlineItems,
                            accessToken,
                            ref fedexErrorMessage
                        );

                        if (fedexOnlineItems.ShipStatus == ShipStatus.Success)
                        {
                            lstOfFile.Add(rate);
                        }
                        else
                        {
                            if (!string.IsNullOrEmpty(fedexErrorMessage))
                            {
                                lstOfError.Add(fedexErrorMessage);
                            }

                            Logger.WriteToLog(Logger.LogType.Error, Constant.FEX_TO_SF, Constant.Id, "GenerateFedexModelRate", "Error during rate calculation: " + fedexErrorMessage);
                        }
                    }

                    recordCount++;
                }
            }
        }
        catch (Exception ex)
        {
            Logger.WriteToLog(Logger.LogType.Error, Constant.SF_TO_FEX, Constant.Id, "GenerateFedexModelRate", ex.Message + " \n " + ex.StackTrace);
        }

        return true;
    }
    #endregion

    #region JSON 
    private string GetPropertyName(JObject jObject)
    {
        string propertyName = string.Empty;
        if (jObject == null)
            return string.Empty;
        foreach (JProperty jProperty in jObject.Properties())
        {
            propertyName = jProperty.Name;
        }
        return propertyName;
    }

    public string GetJsonValue(JToken jToken)
    {
        return (jToken != null) ? Convert.ToString(jToken) : string.Empty;
    }
    #endregion

    #region update token details
    private bool UpdateFedexTokenDetails(FedexHelper fedexHelper)
    {
        bool isSuccess = false;

        try
        {
            var fedexDetails = fedexHelper.any.FedexDetail__r;
            var fedexId = fedexHelper.any.FedexDetail__c;

            if (fedexDetails == null || string.IsNullOrEmpty(fedexId))
                return false;
         

            List<sObject> sObjectList = new List<sObject>();
            sObject obj = new sObject();

            // ✅ Change object type
            obj.type = "FedexDetail__c";

            List<XmlElement> fields = new List<XmlElement>();
            XmlDocument document = new XmlDocument();

            // ✅ Use Name instead of Id
            XmlElement elementName = document.CreateElement("Id");
            elementName.InnerText = fedexDetails.Name;
            fields.Add(elementName);

            // ✅ Access Token
            if (!string.IsNullOrEmpty(fedexDetails.Access_Token__c))
            {
                XmlElement accessToken = document.CreateElement("Access_Token__c");
                accessToken.InnerText = fedexDetails.Access_Token__c;
                fields.Add(accessToken);
            }

            // ✅ Refresh Token
            if (!string.IsNullOrEmpty(fedexDetails.RefreshToken__c))
            {
                XmlElement refreshToken = document.CreateElement("RefreshToken__c");
                refreshToken.InnerText = fedexDetails.RefreshToken__c;
                fields.Add(refreshToken);
            }

            // ✅ Access Token Expiry
            if (fedexDetails.AccessTokenExpire__c.HasValue)
            {
                XmlElement accessExpiry = document.CreateElement("AccessTokenExpire__c");
                accessExpiry.InnerText = fedexDetails.AccessTokenExpire__c.Value.ToString("yyyy-MM-ddTHH:mm:ssZ");
                fields.Add(accessExpiry);
            }

            // ✅ Refresh Token Expiry
            if (fedexDetails.RefreshTokenExpire__c.HasValue)
            {
                XmlElement refreshExpiry = document.CreateElement("RefreshTokenExpire__c");
                refreshExpiry.InnerText = fedexDetails.RefreshTokenExpire__c.Value.ToString("yyyy-MM-ddTHH:mm:ssZ");
                fields.Add(refreshExpiry);
            }

            obj.Any = fields.ToArray();
            sObjectList.Add(obj);

            SaveResult[] results = binding.update(sObjectList.ToArray());

            isSuccess = results[0].success;
        }
        catch (Exception ex)
        {
            Logger.WriteToLog(
                Logger.LogType.Error,
                Constant.FEX_TO_SF,
                Constant.Id,
                "UpdateFedexTokenDetails",
                ex.Message + " \n " + Constant.STACKTRACE + ex.StackTrace
            );
        }

        return isSuccess;
    }
    #endregion
}