#pragma once
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <string>
#include <cstdint>
#include <cstddef>
#include <cstring>
#include "notice.h"

namespace prot {

static constexpr uint32_t FK = 0x51C3A907u;

constexpr uint32_t Mix(uint32_t k, uint32_t i) {
    k ^= 0x9E3779B9u + (i * 0x85EBCA6Bu) + (k << 6) + (k >> 2);
    k *= 16777619u;
    return k ^ (k >> 13);
}

constexpr uint8_t KS(uint32_t seed, size_t i) {
    uint32_t k = Mix(seed ^ 0xA5E319C3u, (uint32_t)i + 1u);
    return uint8_t(k ^ (k >> 8) ^ (k >> 16) ^ (uint8_t)i * 17u);
}

template<size_t N>
struct EBuf {
    uint32_t seed;
    char b[N];
    constexpr EBuf(const char (&s)[N], uint32_t sd) : seed(sd), b{} {
        for (size_t i = 0; i < N; ++i)
            b[i] = char(uint8_t(s[i]) ^ KS(sd, i));
    }
};

inline std::string DecA(const char* e, size_t n, uint32_t seed) {
    std::string r(n, '\0');
    for (size_t i = 0; i < n; ++i)
        r[i] = char(uint8_t(e[i]) ^ KS(seed, i));
    return r;
}

inline std::wstring DecW(const char* e, size_t n, uint32_t seed) {
    auto a = DecA(e, n, seed);
    if (a.empty()) return {};
    int w = MultiByteToWideChar(CP_UTF8, 0, a.c_str(), (int)a.size(), nullptr, 0);
    if (w <= 0) return {};
    std::wstring r((size_t)w, L'\0');
    MultiByteToWideChar(CP_UTF8, 0, a.c_str(), (int)a.size(), r.data(), w);
    return r;
}

float Df(uint32_t enc);
uint32_t Du(uint32_t enc);

bool Init();
void GuardRuntime();

}

#define XS(S)  ([](){ constexpr uint32_t _sd = 0xC31D5A77u ^ (uint32_t)((__LINE__ + __COUNTER__) * 2654435761u); constexpr prot::EBuf<sizeof(S)> _x(S, _sd); return prot::DecA(_x.b, sizeof(S) - 1, _x.seed); }())
#define XSW(S) ([](){ constexpr uint32_t _sd = 0xC31D5A77u ^ (uint32_t)((__LINE__ + __COUNTER__) * 2654435761u); constexpr prot::EBuf<sizeof(S)> _x(S, _sd); return prot::DecW(_x.b, sizeof(S) - 1, _x.seed); }())
