// game/BattlEyeBypass.h
#pragma once

#ifdef CURRENT_MODULE
#undef CURRENT_MODULE
#endif
#define CURRENT_MODULE "BattlEyeBypass"

#include "core/Logger.h"
#include "system/ProcessHandler.h"
#include "core/FilePath.h"
#include <regex>
#include <thread>
#include <chrono>

namespace BattlEyeBypass
{
    inline bool StealCommandLine(std::wstring& outCmdLine)
    {
        LOG_I("Waiting for EscapeFromTarkov_BE.exe to appear");

        for(;;)
        {
            std::vector<DWORD> pids = ProcessHandler::FindProcessesByName(L"EscapeFromTarkov_BE.exe");
            if (pids.empty())
            {
                std::cout << ".";
                std::this_thread::sleep_for(std::chrono::seconds(1));
                continue;
            }

            std::cout << std::endl;
            LOG_I("Found " + std::to_string(pids.size()) + 
                  (pids.size() > 1 ? " BE instances" : " BE instance"));

            bool stolen = false;
            for (DWORD pid : pids)
            {
                LOG_I("Reading command line from PID " + std::to_string(pid));
                std::wstring cmd = ProcessHandler::detail::GetCommandLineFromPid(pid);

                if (!cmd.empty())
                {
                    outCmdLine = std::move(cmd);
                    stolen = true;
                    LOG_I("Command line stolen successfully");
                }
                else
                {
                    LOG_W("Failed to read command line from PID " + std::to_string(pid));
                }

                if (ProcessHandler::TerminateProcessByPid(pid))
                    LOG_I("BE process terminated (PID " + std::to_string(pid) + ")");
                else
                    LOG_E("Failed to terminate PID " + std::to_string(pid));
            }

            return stolen;
        }
    }

    inline std::wstring CleanCommandLine(const std::wstring& stolen)
    {
        std::wregex rx(L"EscapeFromTarkov_BE\\.exe", std::regex_constants::icase);
        return std::regex_replace(stolen, rx, L"EscapeFromTarkov.exe");
    }

    inline std::wstring ExtractExePath(const std::wstring& cmdline)
    {
        std::wsmatch m;
        if (std::regex_search(cmdline, m, std::wregex(L"\"([^\"]+)\"")))
            return m[1].str();

        size_t space = cmdline.find(L' ');
        if (space != std::wstring::npos)
            return cmdline.substr(0, space);

        return cmdline;
    }

    inline std::wstring ExtractWorkingDir(const std::wstring& exePath)
    {
        size_t pos = exePath.find_last_of(L"\\/");
        if (pos == std::wstring::npos)
            return L".";
        return exePath.substr(0, pos);
    }

    struct GameLaunchInfo
    {
        std::wstring ExePath;
        std::wstring WorkingDir;
        std::wstring CleanCmdLine;
    };

    inline bool PrepareLaunchInfo(GameLaunchInfo& outInfo)
    {
        std::wstring stolenCmdLine;
        if (!StealCommandLine(stolenCmdLine))
        {
            LOG_E("Failed to steal any BE command line");
            return false;
        }

        std::wstring clean = CleanCommandLine(stolenCmdLine);
        std::wstring exePath = ExtractExePath(clean);
        std::wstring workDir = ExtractWorkingDir(exePath);

        LOG_I("Game executable   : " + std::string(exePath.begin(), exePath.end()));
        LOG_I("Working directory : " + std::string(workDir.begin(), workDir.end()));

#ifdef _DEBUG
        LOG_I("Command line: " + std::string(clean.begin(), clean.end()));
#endif

        outInfo.ExePath = std::move(exePath);
        outInfo.WorkingDir = std::move(workDir);
        outInfo.CleanCmdLine = std::move(clean);

        return true;
    }
}