//+------------------------------------------------------------------+
//| VNFCommon.mqh — shared helpers for VNF Tracker and License SDK    |
//| VNFUNDED EA HUB                                                   |
//+------------------------------------------------------------------+
#ifndef __VNF_COMMON_MQH__
#define __VNF_COMMON_MQH__

//--- ISO-8601 UTC timestamp "YYYY-MM-DDTHH:MM:SSZ" from a GMT datetime
string VNFIsoUtc(const datetime gmt)
{
   MqlDateTime t; TimeToStruct(gmt, t);
   return StringFormat("%04d-%02d-%02dT%02d:%02d:%02dZ", t.year, t.mon, t.day, t.hour, t.min, t.sec);
}

//--- Broker server offset to UTC (seconds), rounded to 15 minutes. Deal times are SERVER time.
int VNFServerOffset()
{
   long diff = (long)TimeTradeServer() - (long)TimeGMT();
   return (int)(MathRound((double)diff / 900.0) * 900.0);
}
datetime VNFServerToUtc(const datetime serverTime) { return (datetime)((long)serverTime - VNFServerOffset()); }

//--- JSON string escaping
string VNFJsonEscape(string s)
{
   StringReplace(s, "\\", "\\\\");
   StringReplace(s, "\"", "\\\"");
   StringReplace(s, "\r", " ");
   StringReplace(s, "\n", " ");
   StringReplace(s, "\t", " ");
   return s;
}

//--- double -> JSON number (no locale issues, no NaN/Inf)
string VNFNum(const double v, const int digits = 8)
{
   if(!MathIsValidNumber(v)) return "0";
   return DoubleToString(v, digits);
}

//--- minimal JSON readers (enough for the API envelope)
string VNFJsonString(const string json, const string key)
{
   string needle = "\"" + key + "\":\"";
   int p = StringFind(json, needle);
   if(p < 0) return "";
   p += StringLen(needle);
   int e = StringFind(json, "\"", p);
   if(e < 0) return "";
   return StringSubstr(json, p, e - p);
}
bool VNFJsonBool(const string json, const string key, bool &out)
{
   string needle = "\"" + key + "\":";
   int p = StringFind(json, needle);
   if(p < 0) return false;
   p += StringLen(needle);
   if(StringSubstr(json, p, 4) == "true")  { out = true;  return true; }
   if(StringSubstr(json, p, 5) == "false") { out = false; return true; }
   return false;
}
long VNFJsonLong(const string json, const string key, const long def = 0)
{
   string needle = "\"" + key + "\":";
   int p = StringFind(json, needle);
   if(p < 0) return def;
   p += StringLen(needle);
   string digits = "";
   for(int i = p; i < StringLen(json); i++)
   {
      ushort c = StringGetCharacter(json, i);
      if((c >= '0' && c <= '9') || (c == '-' && digits == "")) digits += ShortToString(c); else break;
   }
   return digits == "" ? def : StringToInteger(digits);
}

//--- HTTP POST JSON. Returns HTTP status (or -1 on transport error).
int VNFPost(const string url, const string bearer, const string body, string &response, const int timeoutMs = 15000)
{
   char data[], result[];
   string resultHeaders;
   int len = StringToCharArray(body, data, 0, WHOLE_ARRAY, CP_UTF8);
   if(len > 0) ArrayResize(data, len - 1); // strip trailing \0
   string headers = "Content-Type: application/json\r\nAccept: application/json\r\n";
   if(bearer != "") headers += "Authorization: Bearer " + bearer + "\r\n";
   ResetLastError();
   int status = WebRequest("POST", url, headers, timeoutMs, data, result, resultHeaders);
   if(status == -1)
   {
      int err = GetLastError();
      if(err == 4014) Print("VNF: add the API host to Tools > Options > Expert Advisors > Allow WebRequest: ", url);
      response = "";
      return -1;
   }
   response = CharArrayToString(result, 0, WHOLE_ARRAY, CP_UTF8);
   return status;
}

#endif
