#include "sierrachart.h"
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <map>
#include <ctime>
#include <sstream> 

// Numele DLL-ului
SCDLLName("AI Order Executor v3")

// Structura pentru ordine
struct Order {
    char symbol[32];
    char direction[16];
    char orderType[16];
    double price;
    double stopLoss;
    double takeProfit;
    int quantity;
    char orderId[64];
    char strategy[32];
    int confidence;
    char signalId[64];
};

// Variabile globale
static std::vector<Order> pendingOrders;
static std::map<std::string, int> orderStatus; // Pentru a urmări starea ordinelor
static bool ordersLocked = false;

// Directorul pentru schimb de fisiere
#define ORDERS_DIR "X:\\SierraChart\\AI_Orders"
#define FEEDBACK_DIR "X:\\SierraChart\\AI_Feedback"

// Funcție helper pentru a genera un ID unic pentru fiecare ordin
std::string generateUniqueOrderId() {
    std::stringstream ss;
    ss << "ord_" << time(0) << "_" << rand();
    return ss.str();
}

// Funcție pentru a verifica dacă un ordin este valid
bool isValidOrder(const Order& order) {
    if (strlen(order.symbol) == 0 || strlen(order.direction) == 0) {
        return false;
    }
    // Alte verificări de validare a ordinului, dacă este necesar
    return true;
}

// Declarație forward pentru SendOrderFeedback
void SendOrderFeedback(SCStudyInterfaceRef& sc, const char* orderId, const char* status, double fillPrice,
                       int fillQuantity, double pnl, const char* message,
                       const char* direction, double entryPrice, const char* strategy,
                       int confidence, const char* signalId);

// Funcție pentru a încărca ordinele din fișiere
void LoadOrdersFromFiles(SCStudyInterfaceRef& sc) {
    if (ordersLocked) return;
    ordersLocked = true;

    WIN32_FIND_DATA findFileData;
    HANDLE hFind = FindFirstFile(ORDERS_DIR "\\*.order", &findFileData);

    if (hFind != INVALID_HANDLE_VALUE) {
        do {
            std::string filePath = std::string(ORDERS_DIR) + "\\" + findFileData.cFileName;
            std::ifstream orderFile(filePath);
            if (orderFile.is_open()) {
                Order newOrder;
                memset(&newOrder, 0, sizeof(newOrder));

                std::string line;
                while (std::getline(orderFile, line)) {
                    size_t pos = line.find('=');
                    if (pos != std::string::npos) {
                        std::string key = line.substr(0, pos);
                        std::string value = line.substr(pos + 1);
                        if (key == "symbol") strncpy_s(newOrder.symbol, value.c_str(), sizeof(newOrder.symbol) - 1);
                        else if (key == "direction") strncpy_s(newOrder.direction, value.c_str(), sizeof(newOrder.direction) - 1);
                        else if (key == "orderType") strncpy_s(newOrder.orderType, value.c_str(), sizeof(newOrder.orderType) - 1);
                        else if (key == "price") newOrder.price = atof(value.c_str());
                        else if (key == "stopLoss") newOrder.stopLoss = atof(value.c_str());
                        else if (key == "takeProfit") newOrder.takeProfit = atof(value.c_str());
                        else if (key == "quantity") newOrder.quantity = atoi(value.c_str());
                        else if (key == "orderId") strncpy_s(newOrder.orderId, value.c_str(), sizeof(newOrder.orderId) - 1);
                        else if (key == "strategy") strncpy_s(newOrder.strategy, value.c_str(), sizeof(newOrder.strategy) - 1);
                        else if (key == "confidence") newOrder.confidence = atoi(value.c_str());
                        else if (key == "signalId") strncpy_s(newOrder.signalId, value.c_str(), sizeof(newOrder.signalId) - 1);
                    }
                }
                orderFile.close();

                // Generează un ID unic pentru ordin dacă nu este deja specificat
                if (strlen(newOrder.orderId) == 0) {
                    strncpy_s(newOrder.orderId, generateUniqueOrderId().c_str(), sizeof(newOrder.orderId) - 1);
                }

                // Adaugă ordinul la listă dacă este valid
                if (isValidOrder(newOrder)) {
                    pendingOrders.push_back(newOrder);
                    // Inițializează starea ordinului ca "submitted"
                    orderStatus[newOrder.orderId] = 1; 

                    // Trimitem feedback inițial de "submitted"
                    SendOrderFeedback(sc, newOrder.orderId, "submitted", 0, 0, 0, "Ordin trimis",
                                     newOrder.direction, newOrder.price, newOrder.strategy,
                                     newOrder.confidence, newOrder.signalId);
                }
                else {
                    SCString message;
                    message.Format("Ordin invalid pentru %s, ID: %s", newOrder.symbol, newOrder.orderId);
                    sc.AddMessageToLog(message, 1);
                }

                DeleteFile(filePath.c_str());
            }
        } while (FindNextFile(hFind, &findFileData) != 0);
        FindClose(hFind);
    }

    ordersLocked = false;
}

// Funcție pentru a trimite feedback despre ordine
void SendOrderFeedback(SCStudyInterfaceRef& sc, const char* orderId, const char* status, double fillPrice,
                       int fillQuantity, double pnl, const char* message,
                       const char* direction, double entryPrice, const char* strategy,
                       int confidence, const char* signalId) {
    if (strlen(orderId) == 0) return;

    CreateDirectory(FEEDBACK_DIR, NULL);

    char filename[256];
    sprintf_s(filename, FEEDBACK_DIR "\\%s.feedback", orderId);

    std::ofstream feedbackFile(filename);
    if (feedbackFile.is_open()) {
        feedbackFile << "orderId=" << orderId << std::endl;
        feedbackFile << "status=" << status << std::endl;
        feedbackFile << "direction=" << direction << std::endl;
        feedbackFile << "entryPrice=" << entryPrice << std::endl;
        feedbackFile << "fillPrice=" << fillPrice << std::endl;
        feedbackFile << "fillQuantity=" << fillQuantity << std::endl;
        feedbackFile << "pnl=" << pnl << std::endl;
        feedbackFile << "strategy=" << strategy << std::endl;
        feedbackFile << "confidence=" << confidence << std::endl;
        feedbackFile << "message=" << message << std::endl;
        feedbackFile << "signalId=" << signalId << std::endl;

        feedbackFile.close();
    }

    // Actualizează starea ordinului
    if (strcmp(status, "filled") == 0) {
        orderStatus[orderId] = 2; // "filled"
    }
    else if (strcmp(status, "rejected") == 0) {
        orderStatus[orderId] = 3; // "rejected"
    }
    // ... other statuses
}

// Funcție pentru plasarea ordinelor de ieșire (Stop Loss și Take Profit)
bool PlaceExitOrders(SCStudyInterfaceRef& sc, const Order& order, int entryResult, bool isBuy) {
    if (entryResult <= 0) {
        SCString message;
        message.Format("Nu s-au plasat ordine SL/TP pentru %s - ordinul principal nu a fost executat", order.symbol);
        sc.AddMessageToLog(message, 1);
        return false;
    }

    bool success = true;

    if (order.stopLoss > 0) {
        s_SCNewOrder StopOrder;
        StopOrder.OrderQuantity = order.quantity;
        StopOrder.Symbol = order.symbol;
        StopOrder.OrderType = SCT_ORDERTYPE_STOP;
        StopOrder.Price1 = order.stopLoss;

        int StopResult = isBuy ? sc.SellExit(StopOrder) : sc.BuyExit(StopOrder);
        if (StopResult <= 0) {
            SCString message;
            message.Format("Eroare la plasarea Stop Loss pentru %s: %d", order.symbol, StopResult);
            sc.AddMessageToLog(message, 1);
            success = false;
        }
    }

    if (order.takeProfit > 0) {
        s_SCNewOrder TakeProfitOrder;
        TakeProfitOrder.OrderQuantity = order.quantity;
        TakeProfitOrder.Symbol = order.symbol;
        TakeProfitOrder.OrderType = SCT_ORDERTYPE_LIMIT;
        TakeProfitOrder.Price1 = order.takeProfit;

        int TPResult = isBuy ? sc.SellExit(TakeProfitOrder) : sc.BuyExit(TakeProfitOrder);
        if (TPResult <= 0) {
            SCString message;
            message.Format("Eroare la plasarea Take Profit pentru %s: %d", order.symbol, TPResult);
            sc.AddMessageToLog(message, 1);
            success = false;
        }
    }

    return success;
}

// Funcția principală a studiului
SCSFExport scsf_AIOrderExecutor(SCStudyInterfaceRef sc) {
    SCInputRef Input_EnableOrderExecution = sc.Input[0];
    SCInputRef Input_OrdersDir = sc.Input[1];
    SCInputRef Input_FeedbackDir = sc.Input[2];
    SCInputRef Input_DebugMode = sc.Input[3];

    if (sc.SetDefaults) {
        sc.GraphName = "AI Order Executor v3";
        sc.StudyDescription = "Execută ordine de la sistemul AI folosind schimb de fișiere";

        Input_EnableOrderExecution.Name = "Activare execuție ordine";
        Input_EnableOrderExecution.SetYesNo(0);

        Input_OrdersDir.Name = "Director pentru ordine";
        Input_OrdersDir.SetString(ORDERS_DIR);

        Input_FeedbackDir.Name = "Director pentru feedback";
        Input_FeedbackDir.SetString(FEEDBACK_DIR);

        Input_DebugMode.Name = "Mod debug (afișare mesaje)";
        Input_DebugMode.SetYesNo(0);

        return;
    }

    if (sc.Index == 0) {
        CreateDirectory(Input_OrdersDir.GetString(), NULL);
        CreateDirectory(Input_FeedbackDir.GetString(), NULL);
    }

    if (Input_EnableOrderExecution.GetYesNo()) {
        LoadOrdersFromFiles(sc);

        if (!pendingOrders.empty() && !ordersLocked) {
            ordersLocked = true;
            std::vector<Order> ordersToProcess = pendingOrders;
            pendingOrders.clear();
            ordersLocked = false;

            for (const Order& order : ordersToProcess) {
                if (Input_DebugMode.GetYesNo()) {
                    SCString message;
                    message.Format("Procesare ordin %s: %s %s la %.2f (Stop: %.2f, Target: %.2f, Signal ID: %s)",
                                  order.orderId, order.direction, order.symbol,
                                  order.price, order.stopLoss, order.takeProfit, order.signalId);
                    sc.AddMessageToLog(message, 1);
                }

                s_SCNewOrder NewOrder;
                NewOrder.OrderQuantity = order.quantity;
                NewOrder.Symbol = order.symbol;

                if (strcmp(order.orderType, "market") == 0) {
                    NewOrder.OrderType = SCT_ORDERTYPE_MARKET;
                } else if (strcmp(order.orderType, "limit") == 0) {
                    NewOrder.OrderType = SCT_ORDERTYPE_LIMIT;
                    NewOrder.Price1 = order.price;
                } else if (strcmp(order.orderType, "stop") == 0) {
                    NewOrder.OrderType = SCT_ORDERTYPE_STOP;
                    NewOrder.Price1 = order.price;
                }

                int Result = (strcmp(order.direction, "buy") == 0) ? sc.BuyEntry(NewOrder) : sc.SellEntry(NewOrder);

                if (Result > 0) {
                    double fillPrice = sc.Close[sc.Index];
                    SendOrderFeedback(sc, order.orderId, "filled", fillPrice, order.quantity, 0,
                                     "Ordin executat cu succes", order.direction, order.price,
                                     order.strategy, order.confidence, order.signalId);

                    // Plasăm ordinele de ieșire
                    bool exitOrdersPlaced = PlaceExitOrders(sc, order, Result, strcmp(order.direction, "buy") == 0);
                    if (!exitOrdersPlaced) {
                        sc.AddMessageToLog("Ordinele de Stop Loss și Take Profit nu au putut fi plasate.", 1);
                    }
                }
                else {
                    char errorMsg[256];
                    sprintf_s(errorMsg, "Eroare la executarea ordinului: %d", Result);
                    SendOrderFeedback(sc, order.orderId, "rejected", 0, 0, 0,
                                     errorMsg, order.direction, order.price,
                                     order.strategy, order.confidence, order.signalId);
                }
            }
        }
    }

    return;
}