#pragma once

// AkiProtect / BinaryProtector SDK markers (Phase A1 / roadmap S1).
//
// Link against AkiProtectSDK32.lib / AkiProtectSDK64.lib / AkiProtectSDK_arm64.lib
// (or the matching import library for your toolchain). The DLL exports are
// empty stubs used only as labels: BinaryProtector_builder finds Begin/End
// pairs, protects the body between them, NOPs the calls, and strips the
// SDK import from the output PE. Ship nothing — the SDK DLL is not required
// at runtime after packing.
//
// Example:
//   #include "AkiProtectSDK.h"
//   int CheckLicense(void) {
//       AkiProtectBeginVirtualization("CheckLicense");
//       // sensitive logic
//       AkiProtectEnd();
//       return 1;
//   }

#if defined(_WIN32) || defined(_WIN64) || defined(__CYGWIN__)

#if defined(AKIPROTECT_SDK_EXPORTS)
#define AKIP_API __declspec(dllexport)
#else
#define AKIP_API __declspec(dllimport)
#endif

#if defined(_M_IX86) || defined(__i386__)
#define AKIP_CALL __stdcall
#else
#define AKIP_CALL
#endif

#else
#define AKIP_API
#define AKIP_CALL
#endif

#ifdef __cplusplus
extern "C" {
#endif

// Generic begin — mode taken from project / --virt-mode (default virtualize).
AKIP_API void AKIP_CALL AkiProtectBegin(const char *markerName);

// Fixed compilation types (mode cannot be overridden by --virt-mode).
AKIP_API void AKIP_CALL AkiProtectBeginVirtualization(const char *markerName);
AKIP_API void AKIP_CALL AkiProtectBeginMutation(const char *markerName);
AKIP_API void AKIP_CALL AkiProtectBeginUltra(const char *markerName);

// Lock-by-key: code gated by license (Ф.8.2). Bytecode is encrypted at
// build time; decrypted only after AkiProtectSetSerialNumber succeeds.
AKIP_API void AKIP_CALL AkiProtectBeginVirtualizationLockByKey(const char *markerName);
AKIP_API void AKIP_CALL AkiProtectBeginUltraLockByKey(const char *markerName);

// End of protected range. Must pair with a Begin* above.
AKIP_API void AKIP_CALL AkiProtectEnd(void);

// ---- Service stubs (optional; filled in later phases) --------------------
// Present so apps can link a stable surface. Implementations return
// conservative defaults until Memory Protection / licensing land.

// Returns 1 if the image was processed by BinaryProtector with SDK strip.
AKIP_API int AKIP_CALL AkiProtectIsProtected(void);

// User-mode debugger check. checkKernel is reserved (ignored in S1).
AKIP_API int AKIP_CALL AkiProtectIsDebuggerPresent(int checkKernel);

// Hypervisor / VM heuristic. Stub returns 0 until wired to runtime.
AKIP_API int AKIP_CALL AkiProtectIsVirtualMachinePresent(void);

// Image CRC. Stub returns 1 (valid) until C2 memory protection.
AKIP_API int AKIP_CALL AkiProtectIsValidImageCRC(void);

// String decrypt stubs (C4). Pass-through of input pointer.
AKIP_API const char * AKIP_CALL AkiProtectDecryptStringA(const char *value);
AKIP_API const wchar_t * AKIP_CALL AkiProtectDecryptStringW(const wchar_t *value);
AKIP_API int AKIP_CALL AkiProtectFreeString(const void *value);

// Virtual file lookup (Ф.7.6.2). Returns pointer to embedded file data
// or NULL if not found. outSize receives the file size on success.
// After packing with --virt-file, the runtime patches this import to
// search the in-memory virtual-file blob. Before packing (dev builds),
// the stub returns NULL.
AKIP_API const void * AKIP_CALL AkiProtectFindVirtualFileA(const char *name, unsigned int *outSize);

// Licensing API (Ф.8.1). After packing with --license-key, the runtime
// patches these imports to the embedded license verification engine.
// Before packing (dev builds), the stub returns NOT_SET / 0 / false.
AKIP_API int  AKIP_CALL AkiProtectSetSerialNumber(const char *serial);
AKIP_API int  AKIP_CALL AkiProtectGetSerialNumberState(void);
AKIP_API int  AKIP_CALL AkiProtectGetSerialNumberData(void *data, int size);
AKIP_API int  AKIP_CALL AkiProtectGetCurrentHWID(char *hwid, int size);

// Activation API (Ф.8.6). After packing with --activation-url, the runtime
// patches these imports to the embedded online activation engine.
// Before packing (dev builds), ActivateOffline returns 0 (fail),
// GetActivationRequest returns 0 (empty).
AKIP_API int  AKIP_CALL AkiProtectActivateOffline(const char *responseString);
AKIP_API int  AKIP_CALL AkiProtectGetActivationRequest(char *buf, int size);

#ifdef __cplusplus
}
#endif

// Optional C++ RAII helper (header-only).
#ifdef __cplusplus

// -----------------------------------------------------------------------------
// Ф.7.7 — Compile-time-encoded string literals (header-only, no runtime dep).
//
// Usage:
//   printf("%s\n", AKI_STR("secret text"));      // narrow
//   wprintf(L"%s\n", AKI_WSTR(L"secret wide"));  // wide
//
// The `AKI_STR(literal)` macro constructs an `aki::EncStr<N>` at compile time.
// The compiler evaluates the constructor as constexpr, so the ENCODED bytes are
// what end up in .rdata — the plaintext literal never ships in the binary.
// At runtime an `aki::DecStr<N>` decodes into a stack buffer whose lifetime is
// the full expression (RAII, no manual free needed).
//
// XOR key: 0xA5 ^ (i * 31) & 0xFF — trivially reversible on purpose; the point
// is defeating `strings` / static pattern matching, not serious cryptanalysis.
// For real key-per-build encryption of payload .rdata, use the C4 layer
// (--string-protect flag at pack time) which encrypts the whole .rdata under
// a per-build XOR key. AKI_STR complements C4: works on data allocated by the
// user's own binary before packing.
//
// AkiProtectFreeString(p) is a no-op (buffers are stack-allocated). Kept for
// API-symmetry parity with VMProtect's cpDecryptString family.
//
// **Compile with /O1 or /O2** (MSVC) / -O1+ (clang/gcc) for the plaintext to be
// actually scrubbed from .rdata. At /Od the compiler still emits the source
// literal because the constexpr constructor reads it. Verified via `grep`
// pattern check on aki_str_demo.exe: 0 hits at /O2, 1 hit at /Od.
// -----------------------------------------------------------------------------

namespace aki {

// Same rotating XOR the runtime C4 layer uses for compile-time obfuscation
// of internal stub strings (see bp_strenc.h). Fully constexpr.
constexpr unsigned char aki_str_key(unsigned i) {
    return static_cast<unsigned char>(0xA5u ^ static_cast<unsigned char>(i * 31u));
}

// Encoded narrow-string literal. `data` holds the XOR-encoded bytes.
template <size_t N>
struct EncStr {
    char data[N];
    constexpr EncStr(const char (&s)[N]) : data{} {
        for (size_t i = 0; i < N; ++i)
            data[i] = static_cast<char>(static_cast<unsigned char>(s[i]) ^ aki_str_key(static_cast<unsigned>(i)));
    }
};

// Encoded wide-string literal. Applies the same XOR to each byte of each wchar
// (endianness-agnostic; both sides use the same encoding).
template <size_t N>
struct EncStrW {
    wchar_t data[N];
    constexpr EncStrW(const wchar_t (&s)[N]) : data{} {
        for (size_t i = 0; i < N; ++i) {
            unsigned lo = static_cast<unsigned>(static_cast<unsigned short>(s[i]) & 0xFFu);
            unsigned hi = static_cast<unsigned>(static_cast<unsigned short>(s[i]) >> 8);
            lo ^= aki_str_key(static_cast<unsigned>(i * 2 + 0));
            hi ^= aki_str_key(static_cast<unsigned>(i * 2 + 1));
            data[i] = static_cast<wchar_t>((hi << 8) | (lo & 0xFFu));
        }
    }
};

// Stack-buffered decoded string. Lifetime = surrounding full-expression.
template <size_t N>
struct DecStr {
    char buf[N];
    DecStr(const EncStr<N>& e) {
        for (size_t i = 0; i < N; ++i)
            buf[i] = static_cast<char>(static_cast<unsigned char>(e.data[i]) ^ aki_str_key(static_cast<unsigned>(i)));
    }
    operator const char*() const { return buf; }
    const char* c_str() const { return buf; }
};

template <size_t N>
struct DecStrW {
    wchar_t buf[N];
    DecStrW(const EncStrW<N>& e) {
        for (size_t i = 0; i < N; ++i) {
            unsigned lo = static_cast<unsigned>(static_cast<unsigned short>(e.data[i]) & 0xFFu);
            unsigned hi = static_cast<unsigned>(static_cast<unsigned short>(e.data[i]) >> 8);
            lo ^= aki_str_key(static_cast<unsigned>(i * 2 + 0));
            hi ^= aki_str_key(static_cast<unsigned>(i * 2 + 1));
            buf[i] = static_cast<wchar_t>((hi << 8) | (lo & 0xFFu));
        }
    }
    operator const wchar_t*() const { return buf; }
    const wchar_t* c_str() const { return buf; }
};

} // namespace aki

// The literal MUST be a real string literal (const char[N] / const wchar_t[N]).
// A `const char*` variable will not compile (sizeof would be wrong).
#define AKI_STR(literal)  \
    (aki::DecStr<sizeof(literal)>(aki::EncStr<sizeof(literal)>(literal)))
#define AKI_WSTR(literal) \
    (aki::DecStrW<sizeof(literal)/sizeof(wchar_t)>(aki::EncStrW<sizeof(literal)/sizeof(wchar_t)>(literal)))

namespace aki {
struct ProtectScope {
    explicit ProtectScope(const char *name) { AkiProtectBegin(name); }
    ~ProtectScope() { AkiProtectEnd(); }
    ProtectScope(const ProtectScope &) = delete;
    ProtectScope &operator=(const ProtectScope &) = delete;
};
struct ProtectVirtScope {
    explicit ProtectVirtScope(const char *name) { AkiProtectBeginVirtualization(name); }
    ~ProtectVirtScope() { AkiProtectEnd(); }
    ProtectVirtScope(const ProtectVirtScope &) = delete;
    ProtectVirtScope &operator=(const ProtectVirtScope &) = delete;
};
struct ProtectMutScope {
    explicit ProtectMutScope(const char *name) { AkiProtectBeginMutation(name); }
    ~ProtectMutScope() { AkiProtectEnd(); }
    ProtectMutScope(const ProtectMutScope &) = delete;
    ProtectMutScope &operator=(const ProtectMutScope &) = delete;
};
struct ProtectUltraScope {
    explicit ProtectUltraScope(const char *name) { AkiProtectBeginUltra(name); }
    ~ProtectUltraScope() { AkiProtectEnd(); }
    ProtectUltraScope(const ProtectUltraScope &) = delete;
    ProtectUltraScope &operator=(const ProtectUltraScope &) = delete;
};
struct ProtectVirtLockScope {
    explicit ProtectVirtLockScope(const char *name) { AkiProtectBeginVirtualizationLockByKey(name); }
    ~ProtectVirtLockScope() { AkiProtectEnd(); }
    ProtectVirtLockScope(const ProtectVirtLockScope &) = delete;
    ProtectVirtLockScope &operator=(const ProtectVirtLockScope &) = delete;
};
struct ProtectUltraLockScope {
    explicit ProtectUltraLockScope(const char *name) { AkiProtectBeginUltraLockByKey(name); }
    ~ProtectUltraLockScope() { AkiProtectEnd(); }
    ProtectUltraLockScope(const ProtectUltraLockScope &) = delete;
    ProtectUltraLockScope &operator=(const ProtectUltraLockScope &) = delete;
};
} // namespace aki
#endif
