// system/ServiceManager.h
#pragma once

#ifdef CURRENT_MODULE
#undef CURRENT_MODULE
#endif
#define CURRENT_MODULE "ServiceManager"

#include "core/Logger.h"
#include <windows.h>
#include <string>

namespace ServiceManager
{
    struct ServiceHandleCloser { void operator()(SC_HANDLE h) const noexcept { if (h) CloseServiceHandle(h); } };
    using UniqueServiceHandle = std::unique_ptr<std::remove_pointer<SC_HANDLE>::type, ServiceHandleCloser>;

    inline bool WaitUntilGone(SC_HANDLE scm, const std::wstring& name, DWORD timeoutMs = 30000)
    {
        const DWORD step = 2000;
        DWORD elapsed = 0;

        LOG_I("Waiting for service deletion: " + std::string(name.begin(), name.end()));

        while (elapsed < timeoutMs)
        {
            elapsed += step;
            Sleep(step);

            system("sc query BEService >nul 2>&1");

            UniqueServiceHandle hSvc{ OpenServiceW(scm, name.c_str(), SERVICE_QUERY_STATUS) };
            if (hSvc)
            {
                CloseServiceHandle(hSvc.get());
                continue;
            }

            if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
            {
                CloseServiceHandle(hSvc.get());
                LOG_I("Service fully deleted from SCM");
                return true;
            }
        }

        LOG_W("Timeout waiting for service deletion (ERROR 1072 may occur)");
        return false;
    }

    inline bool StopService(SC_HANDLE hSvc)
    {
        SERVICE_STATUS status{};
        if (!ControlService(hSvc, SERVICE_CONTROL_STOP, &status))
            return false;

        LOG_I("Sent stop command to service");

        for (int i = 0; i < 40; ++i)
        {
            Sleep(300);
            if (!QueryServiceStatus(hSvc, &status))
                return false;
            if (status.dwCurrentState == SERVICE_STOPPED)
                return true;
        }

        LOG_W("Service did not stop in time");
        return false;
    }

    inline bool Remove(const std::wstring& serviceName)
    {
        UniqueServiceHandle scm{ OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CONNECT) };
        if (!scm)
        {
            LOG_E("OpenSCManager failed: " + std::to_string(GetLastError()));
            return false;
        }

        UniqueServiceHandle hSvc{ OpenServiceW(scm.get(), serviceName.c_str(),
            SERVICE_STOP | SERVICE_QUERY_STATUS | DELETE) };

        if (!hSvc)
        {
            if (GetLastError() == ERROR_SERVICE_DOES_NOT_EXIST)
            {
                LOG_I("Service does not exist, nothing to delete");
                return true;
            }

            LOG_E("OpenService failed: " + std::to_string(GetLastError()));
            return false;
        }

        system("taskkill /f /im service.exe >nul 2>&1");

        StopService(hSvc.get());

        if (DeleteService(hSvc.get()))
        {
            LOG_I("DeleteService command sent");
            CloseServiceHandle(hSvc.get());
            return WaitUntilGone(scm.get(), serviceName);
        }

        DWORD err = GetLastError();
        if (err != ERROR_SERVICE_MARKED_FOR_DELETE)
        {
            LOG_E("DeleteService failed: " + std::to_string(err));
            return false;
        }
        LOG_I("Service already marked for delete");
    }

    inline bool DeployFakeBEService(const std::wstring& fakeExePath)
    {
        UniqueServiceHandle scm{ OpenSCManagerW(nullptr, nullptr, SC_MANAGER_CREATE_SERVICE) };
        if (!scm)
        {
            LOG_E("OpenSCManager(create) failed: " + std::to_string(GetLastError()));
            return false;
        }

		// Just create and start the service
        UniqueServiceHandle hSvc{ CreateServiceW(
            scm.get(), L"BEService", L"BattlEye Service",
            SERVICE_START | SERVICE_QUERY_STATUS,
            SERVICE_WIN32_OWN_PROCESS,
            SERVICE_AUTO_START,
            SERVICE_ERROR_NORMAL,
            fakeExePath.c_str(),
            nullptr, nullptr, nullptr, nullptr, nullptr) };

        if (hSvc)
            return StartServiceW(hSvc.get(), 0, nullptr) || 
                   GetLastError() == ERROR_SERVICE_ALREADY_RUNNING;

        // if failed to create the service, delete the service by force and then create
        DWORD err = GetLastError();
        if (err != ERROR_SERVICE_EXISTS && err != ERROR_SERVICE_MARKED_FOR_DELETE)
        {
            LOG_E("CreateService failed: " + std::to_string(err));
            return false;
        }

        LOG_W("Service conflict detected, forcing cleanup...");
        if (!Remove(L"BEService"))
            return false;

        // retry
        hSvc.reset(CreateServiceW(scm.get(), L"BEService", L"BattlEye Service",
            SERVICE_START | SERVICE_QUERY_STATUS,
            SERVICE_WIN32_OWN_PROCESS, SERVICE_AUTO_START,
            SERVICE_ERROR_NORMAL, fakeExePath.c_str(),
            nullptr, nullptr, nullptr, nullptr, nullptr));

        if (!hSvc)
        {
            LOG_E("Retry CreateService failed: " + std::to_string(GetLastError()));
            return false;
        }

        bool started = StartServiceW(hSvc.get(), 0, nullptr);
        if (!started && GetLastError() != ERROR_SERVICE_ALREADY_RUNNING)
        {
            LOG_W("StartService failed: " + std::to_string(GetLastError()));
            return false;
        }

        LOG_I("Fake BEService is running");
        return true;
    }
}