//+------------------------------------------------------------------+
//|                                              blTelegramToMT4.mq4 |
//|                                  Copyright 2025, MQL Development |
//|                                  https://www.mqldevelopment.com/ |
//+------------------------------------------------------------------+
#property copyright "Copyright 2025, MQL Development"
#property link      "https://www.mqldevelopment.com/"
#property version   "1.1"
#property strict

#define buy "buy"
#define sell "sell"
#define MaxOrders 10000

struct msgDetails
  {
   int               msgid;
                     msgDetails()
     {
      msgid       = -1;
     }
  };

msgDetails od[MaxOrders];

input       string               Settings              = " ------------- General Settings ------------- ";   //_
input       int                  magic_no              = 333;                                                // Magic no
input       string               symbolMatch           = "GOLD:XAUUSD,BitCoin:BTCUSD";                       // Symbol Mapping (Telegram:MT4)
input       string               suffix                = "";                                                 // Account Suffix
input       string               prefix                = "";                                                 // Account Prefix
input       double               lotSize               = 0.1;                                                // Lot Size

//+------------------------------------------------------------------+
//| Expert initialization function                                   |
//+------------------------------------------------------------------+
// Global Variables
string      url1      = "http://myapp.local";///"http://127.0.0.1";
string      header    = "Content-Type: application/json\r\nAccept: application/json\r\n";

string symbolChart[];
string symbolSnd[];
string symbolsListUserInput[];
uchar  sym1[];
uchar  sym2[];
int last_message_id = INT_MIN;
int OnInit()
  {
//--- create timer

   ushort u_sep = StringGetCharacter(",",0);
   StringSplit(symbolMatch,u_sep,symbolsListUserInput);
   ArrayResize(symbolChart,0);
   ArrayResize(symbolSnd,0);

   for(int i = 0; i < ArraySize(symbolsListUserInput); i++)
     {

      string str = symbolsListUserInput[i];

      int index  = StringFind(str,":");
      int index2 = StringLen(str);

      ArrayResize(sym1,0);
      ArrayResize(sym2,0);

      for(int j = 0; j < index; j++)
        {
         ArrayResize(sym1,ArraySize(sym1)+1);
         sym1[j] = uchar(str[j]);
        }

      int k = 0;

      for(int j = index + 1 ; j < index2; j++)
        {
         ArrayResize(sym2,ArraySize(sym2)+1);
         sym2[k] = uchar(str[j]);
         k++;
        }

      ArrayResize(symbolChart,ArraySize(symbolChart)+1);
      ArrayResize(symbolSnd,ArraySize(symbolSnd)+1);

      symbolChart[i] = CharArrayToString(sym1);
      symbolSnd[i]   = CharArrayToString(sym2);

     }

   string jsonString = GET_function(url1 + "/get-latest-message-id", header);
   StringReplace(jsonString,"},", "*");
   last_message_id = (int)getJsonStringValue(jsonString, "id") != 0 ? (int)getJsonStringValue(jsonString, "id") : INT_MIN;

   string message = getJsonStringValue(jsonString, "message");

   if(last_message_id != INT_MIN)
     {
      Print(" latest_message_id = ",last_message_id);
      Print(" result found against get-latest-message-id = ",message);
     }

   EventSetTimer(1);

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//| Expert deinitialization function                                 |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {
//--- destroy timer
   EventKillTimer();

  }
//+------------------------------------------------------------------+
//| Expert tick function                                             |
//+------------------------------------------------------------------+
void OnTick()
  {
//---

  }
//+------------------------------------------------------------------+
//| Timer function                                                   |
//+------------------------------------------------------------------+
void OnTimer()
  {
//---
   if(last_message_id == INT_MIN)
     {

      string jsonString = GET_function(url1 + "/get-latest-message-id", header);
      StringReplace(jsonString,"},", "*");
      last_message_id = (int)getJsonStringValue(jsonString, "id") != 0 ? (int)getJsonStringValue(jsonString, "id") : INT_MIN;


      if(last_message_id != INT_MIN)
        {

         string message = getJsonStringValue(jsonString, "message");

         if(last_message_id != INT_MIN)
           {
            Print(" latest_message_id = ",last_message_id);
            Print(" result found against get-latest-message-id = ",message);
           }
         execute_functionality_on_new_message(last_message_id);

        }

     }
   else
     {
      string jsonString = GET_function(url1 + "/get-latest-message-id", header);
      StringReplace(jsonString,"},", "*");
      int latest_message_id = (int)getJsonStringValue(jsonString, "id") != 0 ? (int)getJsonStringValue(jsonString, "id") : INT_MIN;

      if(last_message_id != latest_message_id)
        {
         for(int i = latest_message_id; i > last_message_id; i--)
           {
            execute_functionality_on_new_message(i);
           }
         last_message_id = latest_message_id;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string  GET_function(string url,string headers)
  {

   string result_string = NULL;
   int timeout          = 10;  // Set the timeout value in seconds

   char result[],data[];
   string resultHeaders;
   int res = WebRequest("GET",url,headers,timeout,data,result,resultHeaders);

   if(res == 200)
     {
      result_string = CharArrayToString(result);
     }
   else
     {
      Print("content GETT: ", result_string," Error: ",GetLastError(), " res: ",res);
     }

   return result_string;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool checkExistingTrade(int message_id)
  {
   for(int i=0; i < MaxOrders; i++)
     {
      if(od[i].msgid == message_id)
        {
         return true;
        }
     }
   return false;
  }

//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string getJsonStringValue(string json,string key,int addUp,string endSign)
  {
   int indexStart = StringFind(json,key)+StringLen(key)+addUp;
   int indexEnd   = StringFind(json,endSign,indexStart);
   return StringSubstr(json,indexStart,indexEnd-indexStart);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string getJsonStringValue(string json, string key)
  {
   int start = StringFind(json, "\""+key+"\"");
   if(start == -1)
      return "";

// Find colon after key
   int colon = StringFind(json, ":", start);
   if(colon == -1)
      return "";

// Find next comma or closing brace
   int endComma = StringFind(json, ",", colon);
   int endBrace = StringFind(json, "}", colon);
   int end = (endComma != -1 && (endComma < endBrace || endBrace == -1)) ? endComma : endBrace;
   if(end == -1)
      end = StringLen(json);

   string value = trim(StringSubstr(json, colon+1, end-colon-1));
// remove quotes if exist
   StringReplace(value, "\"", "");
   return value;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string trim(string text)
  {
   StringTrimLeft(text);
   StringTrimRight(text);
   return text;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void execute_functionality_on_new_message(int i)
  {

   string url = url1 + "/get-message/" + IntegerToString(i);
   string jsonString = GET_function(url, header);
   StringReplace(jsonString,"},", "*");

   string message = getJsonStringValue(jsonString,"message",4,"\"");

   int group_message_id = (int)getJsonStringValue(jsonString, "message_id");

   StringToLower(message);
   StringReplace(message,"~","#");

   if(checkExistingTrade(group_message_id) == false)
     {

      string isReplyValue = getJsonStringValue(jsonString, "is_reply");

      if(isReplyValue == "True")
        {

         int reply_to_msg_id = (int)getJsonStringValue(jsonString, "reply_to_msg_id");
         message = getJsonStringValue(jsonString, "message");
         StringToLower(message);

         Print(" ================ Replied Message found of message_id ================ ",reply_to_msg_id);
         Print(" ================ Message: ================ ",message);

        }

      else
        {
         if(checkExistingTrade(group_message_id) == false)
           {
            Print(" --------------- New Trade Message Found ----------------- ", " Message Id: ", group_message_id);
            StringReplace(message,"~","#");
            StringReplace(message,"##", "#");
            StringToLower(message);
            message = removeExtraSpaces(message);
            Print("Message is ",message);

            string result[];
            string tempResult[];
            int indexTemp = 0;

            StringSplit(message,'#',tempResult);

            for(int j=0; j<ArraySize(tempResult); j++)
              {
               //result[i] = StringTrimLeft(result[i]);
               //result[i] = StringTrimRight(result[i]);
               //Print("Temp Result : ", tempResult[i], " index is: ", i);
               if(HasAlphanumeric(tempResult[j]))
                 {
                  //Print(" contains alphanumeric characters.");
                  ArrayResize(result,ArraySize(result)+1);
                  result[indexTemp] = tempResult[j];
                  indexTemp++;
                 }
               else
                 {
                  //Print(" does not contain alphanumeric characters.");
                  //ArrayResize(indexToDelete,ArraySize(indexToDelete)+1);
                  //indexToDelete[indexTemp] = i;
                  //indexTemp++;
                 }
              }

            addtoMessageStructure(group_message_id,message);

            message(result,message,group_message_id);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void message(string &result[], string message, int message_id)
  {
   string lineOne[]; // = result[0];
   int lineIndex = 0;
   string direction = "";
   int direction_index = -1;
   string symbol = "";

   if(ArraySize(result) >= 1)
     {
      StringSplit(result[0], ' ', lineOne);
      if(((StringFind(result[0], "buy", 0) != -1) || (StringFind(result[0], "sell", 0) != -1)))
        {

         for(int i=0; i<ArraySize(lineOne); i++)
           {
            if(HasAlphanumeric(lineOne[i]))
              {
               ArrayResize(lineOne,ArraySize(lineOne)+1);
               lineOne[lineIndex] = lineOne[i];
               Print("Direction and Symbol: ", lineOne[lineIndex], " index is: ", lineIndex);

               if(lineOne[lineIndex] == buy || lineOne[lineIndex] == sell)
                 {
                  direction = lineOne[lineIndex];
                  direction_index = lineIndex;
                  //Print(" Direction is: ", direction, " Direction Index: ", direction_index);
                 }
               lineIndex++;
              }
           }
         if(ArraySize(lineOne) >= 2)
           {
            if(direction_index == 0)
              {
               symbol = lineOne[1];
               StringToUpper(symbol);

               //Print(" This is Message format One (1). Where Direction is: ", direction, " Symbol: ", symbol);
              }
            else
               if(direction_index > 0)
                 {
                  symbol = lineOne[0];
                  StringToUpper(symbol);

                  //Print(" This is Message format One (1). Where Direction is: ", direction, " Symbol: ", symbol);
                 }
           }
         symbol = symbolMapping(symbol);

         double sl = 0;
         double tp = 0; // = result[0];
         for(int i=0 ; i < ArraySize(result); i++)
           {
            // result[i] = StringTrimLeft(result[i]);
            // result[i] = StringTrimRight(result[i]);
            // Print("Result : ", result[i], " index is: ", i);
            if((StringFind(result[i], "sl", 0) != -1))
              {
               string tempSl[];
               result[i] = trimString(result[i]);
               //Print(" Sl String: ", result[i]);
               StringSplit(result[i], ':', tempSl);
               if(ArraySize(tempSl) >= 2)
                  sl = (double) tempSl[1];
               Print("Sl : ", sl);
              }
            if((StringFind(result[i], "tp", 0) != -1))
              {
               // Print("Tp : ", result[i], " index is: ", i);
               string tempTp[];
               result[i] = trimString(result[i]);
               StringSplit(result[i], ':', tempTp);
               //double tp = (double) tempTp[1];
               if(ArraySize(tempTp) >= 2)
                  tp = (double) tempTp[1];
               Print("Tp : ", tp);
              }
           }
         Print("Side:", direction, " Symbol: ", symbol, " Tp: ", tp, " Sl: ", sl, " Message Id: ", message_id);

         if(direction == buy)
           {
            placeBuyTrade(symbol, tp, sl, message_id, lotSize);
           }

         if(direction == sell)
           {
            placeSellTrade(symbol, tp, sl, message_id, lotSize);
           }
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void placeBuyTrade(string symbol,double tp,double sl, int messageId, double lot_size)
  {

   double ask = SymbolInfoDouble(symbol,SYMBOL_ASK);
   double bid = SymbolInfoDouble(symbol,SYMBOL_BID);
   double buySl  = sl;
   double buyTp  = tp;


   int ticket = OrderSend(symbol, OP_BUY, lot_size, ask, 3, buySl, buyTp, "Buy Trade Placed.", magic_no, 0, clrBlue);
   Print("Buy order Print: Stop Loss: ", buySl, " Take profit: ", buyTp);
   if(ticket < 0)
     {
      Print("Buy Order Failed ", GetLastError());
     }
   else
     {
      Print(" Buy Order Is Placed Sucessfully ");
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void placeSellTrade(string symbol,double tp,double sl, int messageId, double lot_size)
  {

   double ask = SymbolInfoDouble(symbol,SYMBOL_ASK);
   double bid = SymbolInfoDouble(symbol,SYMBOL_BID);
   double sellSl = sl;
   double sellTp = tp;

   int ticket = OrderSend(symbol, OP_SELL, lot_size, bid, 3, sellSl, sellTp, "Sell Trade Placed.", magic_no, 0, clrRed);
   if(ticket < 0)
     {
      Print("Sell Order Failed ", GetLastError());
     }
   else
     {
      Print(" Sell Order Is Placed Sucessfully ");
     }

  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void addtoMessageStructure(int message_id,string message)
  {
   for(int i=0; i < MaxOrders; i++)
     {
      if(od[i].msgid == -1)
        {
         od[i].msgid = message_id;
         StringToLower(message);
         Print(" Message ID ",message_id,"  of Message = ",message," is added To Structure :: ");
         break;
        }
     }
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string trimString(string inputt)
  {
// Remove spaces from the left and right sides
   int start = 0;
   int end = StringLen(inputt) - 1;

// Find the first non-space character
   while(start <= end && StringGetCharacter(inputt, start) == ' ')
      start++;

// Find the last non-space character
   while(end >= start && StringGetCharacter(inputt, end) == ' ')
      end--;

// Extract the substring without leading or trailing spaces
   return StringSubstr(inputt, start, end - start + 1);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string removeExtraSpaces(string str)
  {
   string result = "";
   int len = StringLen(str);
   bool lastWasSpace = false;

   for(int i = 0; i < len; i++)
     {
      string currentChar = StringSubstr(str, i, 1);

      if(currentChar == " ")
        {
         // Skip adding this space if the last character was also a space
         if(lastWasSpace)
            continue;

         lastWasSpace = true;
        }
      else
        {
         lastWasSpace = false;
        }

      result += currentChar;
     }

   return result;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool HasAlphanumeric(string str)
  {
//Print("String Length: ", StringLen(str));
   for(int i = 0; i <= StringLen(str); i++)
     {
      //Print("Here ", StringLen(str));
      if(IsAlphanumeric((char)str[i]))
        {
         return true;
         break;
        }
     }
   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
bool IsAlphanumeric(char c)
  {
   if((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'))
      return true;
   return false;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
string symbolMapping(string symbol)
  {
   for(int k = 0; k < ArraySize(symbolChart); k++)
     {
      StringToUpper(symbolChart[k]);
      if(symbol == symbolChart[k])
        {
         symbol = symbolSnd[k];
        }
     }
   symbol = prefix + symbol + suffix;
   return symbol;
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
//+------------------------------------------------------------------+

//+------------------------------------------------------------------+
