#include <windows.h>
#include <wininet.h>
#include <iostream>
#include <string>
#include <sstream>
#include <vector>
#include <bcrypt.h>
#include <iomanip>

#pragma comment(lib, "wininet.lib")
#pragma comment(lib, "bcrypt.lib")

// API Host and Port Configuration
// In production: Change HOST to your Render domain (e.g. "your-app.onrender.com") and PORT to 443
const std::string API_HOST = "auth.anikxcheatx.com";
const int API_PORT = 80;
const std::string APP_ID = "YOUR_APP_ID"; // Replace with App ID from dashboard

// Helper function to hash text using SHA-256 via Windows Cryptography API (CNG)
std::string CalculateSHA256(const std::string& input) {
    BCRYPT_ALG_HANDLE hAlg = NULL;
    BCRYPT_HASH_HANDLE hHash = NULL;
    std::string hashHex = "";

    if (BCryptOpenAlgorithmProvider(&hAlg, BCRYPT_SHA256_ALGORITHM, NULL, 0) >= 0) {
        DWORD cbHashObject = 0, cbData = 0;
        if (BCryptGetProperty(hAlg, BCRYPT_OBJECT_LENGTH, (PBYTE)&cbHashObject, sizeof(DWORD), &cbData, 0) >= 0) {
            std::vector<BYTE> hashObject(cbHashObject);
            DWORD cbHash = 0;
            if (BCryptGetProperty(hAlg, BCRYPT_HASH_LENGTH, (PBYTE)&cbHash, sizeof(DWORD), &cbData, 0) >= 0) {
                std::vector<BYTE> hashVal(cbHash);
                if (BCryptCreateHash(hAlg, &hHash, hashObject.data(), cbHashObject, NULL, 0, 0) >= 0) {
                    if (BCryptHashData(hHash, (PBYTE)input.c_str(), input.length(), 0) >= 0) {
                        if (BCryptFinishHash(hHash, hashVal.data(), cbHash, 0) >= 0) {
                            std::stringstream ss;
                            for (BYTE b : hashVal) {
                                ss << std::hex << std::setw(2) << std::setfill('0') << (int)b;
                            }
                            hashHex = ss.str();
                        }
                    }
                }
            }
        }
    }

    if (hHash) BCryptDestroyHash(hHash);
    if (hAlg) BCryptCloseAlgorithmProvider(hAlg, 0);
    return hashHex;
}

// Generate unique hardware ID using CPU info / local Volume info
std::string GetHWID() {
    DWORD volumeSerial = 0;
    GetVolumeInformationW(L"C:\\", NULL, 0, &volumeSerial, NULL, NULL, NULL, 0);

    wchar_t computerName[MAX_COMPUTERNAME_LENGTH + 1];
    DWORD size = sizeof(computerName) / sizeof(computerName[0]);
    GetComputerNameW(computerName, &size);

    std::wstring ws(computerName);
    std::string name(ws.begin(), ws.end());

    std::stringstream ss;
    ss << name << "-" << volumeSerial;
    
    return CalculateSHA256(ss.str());
}

// Send HTTP POST request to API using WinINet API
std::string SendPostRequest(const std::string& path, const std::string& jsonPayload) {
    HINTERNET hSession = InternetOpenA("AnikX", INTERNET_OPEN_TYPE_PRECONFIG, NULL, NULL, 0);
    if (!hSession) return "{\"detail\":\"Failed to open internet session.\"}";

    HINTERNET hConnect = InternetConnectA(hSession, API_HOST.c_str(), API_PORT, NULL, NULL, INTERNET_SERVICE_HTTP, 0, 0);
    if (!hConnect) {
        InternetCloseHandle(hSession);
        return "{\"detail\":\"Failed to connect to server.\"}";
    }

    DWORD flags = INTERNET_FLAG_RELOAD | INTERNET_FLAG_NO_CACHE_WRITE;
    if (API_PORT == 443) {
        flags |= INTERNET_FLAG_SECURE;
    }

    HINTERNET hRequest = HttpOpenRequestA(hConnect, "POST", path.c_str(), NULL, NULL, NULL, flags, 0);
    if (!hRequest) {
        InternetCloseHandle(hConnect);
        InternetCloseHandle(hSession);
        return "{\"detail\":\"Failed to open HTTP request.\"}";
    }

    std::string headers = "Content-Type: application/json\r\n";
    BOOL sent = HttpSendRequestA(hRequest, headers.c_str(), headers.length(), (LPVOID)jsonPayload.c_str(), jsonPayload.length());

    std::string response = "";
    if (sent) {
        char buffer[1024];
        DWORD bytesRead = 0;
        while (InternetReadFile(hRequest, buffer, sizeof(buffer) - 1, &bytesRead) && bytesRead > 0) {
            buffer[bytesRead] = '\0';
            response += buffer;
        }
    } else {
        response = "{\"detail\":\"Failed to send request.\"}";
    }

    InternetCloseHandle(hRequest);
    InternetCloseHandle(hConnect);
    InternetCloseHandle(hSession);
    return response;
}

// Extract values from JSON response keys (simple validation helper)
std::string GetJSONValue(const std::string& json, const std::string& key) {
    std::string searchKey = "\"" + key + "\":\"";
    size_t pos = json.find(searchKey);
    if (pos == std::string::npos) return "";
    
    size_t start = pos + searchKey.length();
    size_t end = json.find("\"", start);
    if (end == std::string::npos) return "";
    
    return json.substr(start, end - start);
}

void Register() {
    std::string username, password, key;
    std::cout << "Enter username: ";
    std::cin >> username;
    std::cout << "Enter password: ";
    std::cin >> password;
    std::cout << "Enter license key: ";
    std::cin >> key;

    std::stringstream payload;
    payload << "{\"app_id\":\"" << APP_ID << "\",\"username\":\"" << username << "\",\"password\":\"" << password 
            << "\",\"license_key\":\"" << key << "\",\"hwid\":\"" << GetHWID() << "\"}";

    std::cout << "\n[*] Sending registration request...\n";
    std::string response = SendPostRequest("/api/client/register", payload.str());
    
    std::string status = GetJSONValue(response, "status");
    if (status == "success") {
        std::cout << "[+] Registration Successful! Expiry: " << GetJSONValue(response, "expires_at") << "\n";
    } else {
        std::string detail = GetJSONValue(response, "detail");
        if (detail.empty()) detail = response;
        std::cout << "[-] Registration Failed: " << detail << "\n";
    }
}

bool Login() {
    std::string username, password;
    std::cout << "Enter username: ";
    std::cin >> username;
    std::cout << "Enter password: ";
    std::cin >> password;

    std::stringstream payload;
    payload << "{\"app_id\":\"" << APP_ID << "\",\"username\":\"" << username << "\",\"password\":\"" << password 
            << "\",\"hwid\":\"" << GetHWID() << "\"}";

    std::cout << "\n[*] Sending login request...\n";
    std::string response = SendPostRequest("/api/client/login", payload.str());
    
    std::string status = GetJSONValue(response, "status");
    if (status == "success") {
        std::cout << "[+] Login Successful!\n";
        std::cout << "[+] Expiry: " << GetJSONValue(response, "expires_at") << "\n";
        return true;
    } else {
        std::string detail = GetJSONValue(response, "detail");
        if (detail.empty()) detail = response;
        std::cout << "[-] Login Failed: " << detail << "\n";
        return false;
    }
}

bool LoginByLicense() {
    std::string key;
    std::cout << "Enter your License Key: ";
    std::cin >> key;

    std::stringstream payload;
    payload << "{\"app_id\":\"" << APP_ID << "\",\"license_key\":\"" << key << "\",\"hwid\":\"" << GetHWID() << "\"}";

    std::cout << "\n[*] Sending license login request...\n";
    std::string response = SendPostRequest("/api/client/license_login", payload.str());
    
    std::string status = GetJSONValue(response, "status");
    if (status == "success") {
        std::cout << "[+] License Login Successful!\n";
        std::cout << "[+] Expiry: " << GetJSONValue(response, "expires_at") << "\n";
        return true;
    } else {
        std::string detail = GetJSONValue(response, "detail");
        if (detail.empty()) detail = response;
        std::cout << "[-] License Login Failed: " << detail << "\n";
        return false;
    }
}

int main() {
    std::cout << "=== Anik X Cheats AUTHENTICATION CLIENT (C++) ===\n";
    std::cout << "[DEBUG] HWID: " << GetHWID() << "\n\n";

    if (APP_ID == "YOUR_APP_ID") {
        std::cout << "[WARNING] Please configure your APP_ID at the top of the file before testing!\n";
        std::cout << "------------------------------------------------------------\n";
    }

    while (true) {
        std::cout << "Choose Authentication Method:\n";
        std::cout << "1. Username & Password Auth (Register/Login)\n";
        std::cout << "2. License Key Only Auth (Direct License Login)\n";
        std::cout << "3. Exit\n";
        std::cout << "Select mode (1-3): ";
        int mode;
        std::cin >> mode;

        if (mode == 1) {
            std::cout << "\n--- USERNAME & PASSWORD AUTH ---\n";
            std::cout << "1. Register Account\n";
            std::cout << "2. Login\n";
            std::cout << "Select option (1-2): ";
            int choice;
            std::cin >> choice;

            if (choice == 1) {
                Register();
                std::cout << "----------------------------------------\n";
            } else if (choice == 2) {
                if (Login()) {
                    std::cout << "\n[*] Starting protected application module...\n";
                    system("pause");
                    break;
                } else {
                    std::cout << "[*] Access Denied.\n";
                }
                std::cout << "----------------------------------------\n";
            }
        } else if (mode == 2) {
            std::cout << "\n--- LICENSE KEY ONLY AUTH ---\n";
            if (LoginByLicense()) {
                std::cout << "\n[*] Starting protected application module...\n";
                system("pause");
                break;
            } else {
                std::cout << "[*] Access Denied.\n";
            }
            std::cout << "----------------------------------------\n";
        } else if (mode == 3) {
            break;
        } else {
            std::cout << "[-] Invalid choice. Try again.\n\n";
        }
    }
    return 0;
}
