#include <algorithm>
#include <chrono>
#include <iostream>
#include <random>
#include <string>
#include <vector>

template <typename T>
inline T clampv(T v, T lo, T hi) { return std::max(lo, std::min(v, hi)); }

struct Enemy { std::string name; int hp; int atk; };
struct BattleState { int playerHP = 100; int playerATK = 20; Enemy enemy; };

struct RNG {
    std::mt19937_64 eng;
    RNG() {
        std::random_device rd;
        auto seed = (static_cast<uint64_t>(rd()) << 32) ^ static_cast<uint64_t>(rd());
        eng.seed(seed ^ static_cast<uint64_t>(std::chrono::high_resolution_clock::now().time_since_epoch().count()));
    }
    int uniformInt(int lo, int hi) { std::uniform_int_distribution<int> d(lo, hi); return d(eng); }
    bool chance(double p) { std::bernoulli_distribution d(clampv(p, 0.0, 1.0)); return d(eng); }
};

static const std::vector<Enemy> ENEMIES = {
    {"knight", 50, 15},
    {"soldier", 30, 10},
    {"attacker", 40, 20},
    {"npc", 20, 5},
    {"rogue", 35, 18},
    {"brute", 60, 12},
    {"shade", 25, 25},
    {"reaper", 1, 1},
    {"dragon", 1, 1},
    {"lich", 1, 1}
};
static const std::vector<std::string> SURRENDER_LINES = {
    "I surrender!", "This is too much!", "Have mercy!", "You're too strong!", "I yield!", "No more!"
};
static const std::vector<std::string> ENEMY_TAUNTS = {
    "Take this!", "Die!", "For glory!", "You're finished!", "Your end is near!"
};
static const std::vector<std::string> PLAYER_TAUNTS = {
    "Taste my steel!", "For honor!", "You won't survive!", "This ends now!"
};

int rollDamage(RNG& rng, int baseMax) {
    int a = rng.uniformInt(0, baseMax);
    int b = rng.uniformInt(0, baseMax);
    int biased = a > b ? a : b;
    return clampv(biased, 0, baseMax);
}

int main() {
    RNG rng;
    int idx = rng.uniformInt(0, (int)ENEMIES.size() - 1);
    const Enemy& picked = ENEMIES[idx];
    BattleState st{100, 20, picked};
    std::cout << "You encountered the " << picked.name << "!\n";
    int oneBased = idx + 1;
    if (oneBased >= 8) {
        std::cout << "\nInstant death.\n";
        std::cout << "\nYou were slain by the " << picked.name << "!\n";
        return 0;
    }
    if (oneBased == 6 || oneBased == 7) {
        if (rng.chance(0.5)) {
            std::cout << "\nCoin flip: loss.\n";
            std::cout << "\nYou were slain by the " << picked.name << "!\n";
            return 0;
        } else {
            std::cout << "Coin flip: survive.\n";
        }
    }
    int pre = rng.uniformInt(1, 3);
    if (pre == 1) { int buff = rng.uniformInt(5, 15); st.enemy.hp += buff; std::cout << "Enemy found extra health! (+" << buff << ")\n"; }
    else if (pre == 2) { int buff = rng.uniformInt(10, 20); st.playerHP += buff; std::cout << "You found a health potion! (+" << buff << ")\n"; }
    int turn = 1;
    while (st.playerHP > 0 && st.enemy.hp > 0) {
        std::cout << "\n--- Turn " << turn++ << " ---\n";
        if (rng.chance(0.3)) std::cout << PLAYER_TAUNTS[rng.uniformInt(0, (int)PLAYER_TAUNTS.size() - 1)] << "\n";
        bool enemyFirst = rng.chance(0.5);
        if (enemyFirst) {
            int enemyHit = rollDamage(rng, st.enemy.atk);
            st.playerHP = clampv(st.playerHP - enemyHit, 0, 10000);
            if (rng.chance(0.4)) std::cout << ENEMY_TAUNTS[rng.uniformInt(0, (int)ENEMY_TAUNTS.size() - 1)] << "\n";
            std::cout << "Enemy attacks first! Damage: " << enemyHit << "\n";
            std::cout << "Player HP: " << st.playerHP << "\n";
            if (st.playerHP == 0) break;
        }
        int playerHit = rollDamage(rng, st.playerATK);
        st.enemy.hp = clampv(st.enemy.hp - playerHit, 0, 10000);
        std::cout << "Player attacks! Damage: " << playerHit << "\n";
        std::cout << "Enemy HP: " << st.enemy.hp << "\n";
        if (st.enemy.hp == 0) break;
        if (!enemyFirst) {
            int enemyHit = rollDamage(rng, st.enemy.atk);
            st.playerHP = clampv(st.playerHP - enemyHit, 0, 10000);
            if (rng.chance(0.4)) std::cout << ENEMY_TAUNTS[rng.uniformInt(0, (int)ENEMY_TAUNTS.size() - 1)] << "\n";
            std::cout << "Enemy retaliates! Damage: " << enemyHit << "\n";
            std::cout << "Player HP: " << st.playerHP << "\n";
            if (st.playerHP == 0) break;
        }
        if (st.enemy.hp < 30 && rng.chance(0.5)) std::cout << SURRENDER_LINES[rng.uniformInt(0, (int)SURRENDER_LINES.size() - 1)] << "\n";
    }
    std::cout << (st.playerHP > 0 ? "\nYou defeated the " : "\nYou were slain by the ") << st.enemy.name << "!\n";
    return 0;
}
