#include <iostream>
#include <vector>
#include <conio.h>      // For _getch()
#include <algorithm>    // For std::find
#include <cstdlib>      // For system(), rand()
#include <ctime>        // For time()
#include <cmath>        // For abs()
#include <string>

// Struct for entities (player, enemies, bunkers)
struct Entity {
    int x, y;
    int health;
    char symbol;
};

// Struct for pickups (like medkits)
struct Pickup {
    int x, y;
    char symbol;
    int value; // e.g., health restore
};

// Struct for player weapons
struct Weapon {
    std::string name;
    int range;     // effective shooting range
    int ammo;      // current ammo in clip
    int clipSize;  // max ammo in a clip
};

// Global score variable
int score = 0;

// --------------------
// Battle Encounter System (Turn-Based)
// --------------------

// Function to display a health bar.
void displayHealthBar(const std::string &name, int health, int maxHealth) {
    int barWidth = 20;
    int pos = (health * barWidth) / maxHealth;
    std::cout << name << " Health: [";
    for (int i = 0; i < barWidth; i++) {
        if (i < pos)
            std::cout << "#";
        else
            std::cout << "-";
    }
    std::cout << "] " << health << "/" << maxHealth << std::endl;
}

// Battle encounter function using a turn‐based simulation.
// Returns true if the player wins, false if defeated.
bool battleEncounter(const std::string &battleName, int &playerHealth, int maxPlayerHealth, int enemyHealth) {
    std::cout << "\n=== Battle: " << battleName << " ===\n";
    while (playerHealth > 0 && enemyHealth > 0) {
        // Show current status
        displayHealthBar("Player", playerHealth, maxPlayerHealth);
        std::cout << "Enemy Health: " << enemyHealth << std::endl;
        
        // Player's turn
        std::cout << "Press 's' to shoot: ";
        char action;
        std::cin >> action;
        if (action == 's' || action == 'S') {
            int damage = 10 + rand() % (20 - 10 + 1);
            std::cout << "You shoot the enemy and deal " << damage << " damage!\n";
            enemyHealth -= damage;
            if (enemyHealth <= 0) {
                std::cout << "Enemy defeated!\n";
                break;
            }
        } else {
            std::cout << "Invalid input, you lose your chance to shoot!\n";
        }
        
        // Enemy's turn
        int enemyDamage = 10 + rand() % (15 - 10 + 1);
        std::cout << "Enemy shoots back and deals " << enemyDamage << " damage!\n";
        playerHealth -= enemyDamage;
        if (playerHealth <= 0) {
            std::cout << "You have been defeated in battle: " << battleName << "\n";
            return false;
        }
    }
    return true;
}

// Mini battle function for bunkers in the D-Day campaign.
// Returns true if the player survives and captures the bunker.
bool battleBunker(Entity &bunker, int &playerHealth) {
    int bunkerMaxHealth = bunker.health; // e.g., 50
    std::cout << "\nInitiating Bunker Assault at (" << bunker.x << "," << bunker.y << "). Bunker Health: " << bunker.health << "\n";
    while (bunker.health > 0 && playerHealth > 0) {
        displayHealthBar("Player", playerHealth, 100);
        displayHealthBar("Bunker", bunker.health, bunkerMaxHealth);
        std::cout << "Press 's' to shoot the bunker: ";
        char action;
        std::cin >> action;
        if(action == 's' || action == 'S') {
            int damage = 10 + rand() % (20 - 10 + 1);
            std::cout << "You hit the bunker for " << damage << " damage!\n";
            bunker.health -= damage;
            if(bunker.health <= 0) {
                std::cout << "Bunker destroyed and captured!\n";
                return true;
            }
        } else {
            std::cout << "Invalid input, you missed your chance!\n";
        }
        // Bunker turret counter-attack
        int turretDamage = 5 + rand() % (10 - 5 + 1);
        std::cout << "Bunker turret fires and deals " << turretDamage << " damage to you!\n";
        playerHealth -= turretDamage;
        if(playerHealth <= 0) {
            std::cout << "You have been killed by the bunker defenses!\n";
            return false;
        }
    }
    return true;
}

// --------------------
// Map and Campaign Gameplay
// --------------------

// Function to display the game map and player status.
void render(const std::vector<std::vector<char>>& baseMap, 
            const Entity& player, 
            const std::vector<Entity>& enemies,
            const std::vector<Pickup>& pickups,
            const std::vector<Entity>& bunkers,
            const Weapon& weapon) {
    system("cls"); // Clear console (Windows-specific)
    std::vector<std::vector<char>> displayMap = baseMap;
    
    // Place pickups on the map
    for (const auto& pick : pickups) {
        displayMap[pick.y][pick.x] = pick.symbol;
    }
    
    // Place bunkers (for D-Day)
    for (const auto& bunker : bunkers) {
        displayMap[bunker.y][bunker.x] = bunker.symbol;
    }
    
    // Place enemies
    for (const auto& enemy : enemies) {
        displayMap[enemy.y][enemy.x] = enemy.symbol;
    }
    
    // Place player (draw on top)
    displayMap[player.y][player.x] = player.symbol;
    
    // Print map
    for (const auto& row : displayMap) {
        for (char c : row) {
            std::cout << c << ' ';
        }
        std::cout << std::endl;
    }
    
    // Show status info
    std::cout << "Player Health: " << player.health;
    if (player.health < 30)
        std::cout << "  [WARNING: LOW HEALTH]";
    std::cout << "\nScore: " << score;
    std::cout << "\nWeapon: " << weapon.name << " | Ammo: " << weapon.ammo << "/" << weapon.clipSize << std::endl;
    std::cout << "\nControls:" << std::endl;
    std::cout << "  Movement: w/a/s/d and diagonals (q, e, z, c)" << std::endl;
    std::cout << "  Shooting: i/j/k/l for up/left/down/right" << std::endl;
    std::cout << "  Grenade: g   Reload: r" << std::endl;
}

// Function to add obstacles randomly to the map.
void addObstacles(std::vector<std::vector<char>>& baseMap, int count) {
    int height = baseMap.size();
    int width = baseMap[0].size();
    // Seed once (should ideally be called only once in main, but safe here)
    srand(static_cast<unsigned int>(time(0)));
    int placed = 0;
    while (placed < count) {
        int x = rand() % width;
        int y = rand() % height;
        // Place an obstacle if spot is empty ('.')
        if (baseMap[y][x] == '.') {
            baseMap[y][x] = '#';
            placed++;
        }
    }
}

// Function to run a campaign.
void playCampaign(int campaign) {
    const int MAP_WIDTH = 10;
    const int MAP_HEIGHT = 10;
    
    // Initialize base map
    std::vector<std::vector<char>> baseMap(MAP_HEIGHT, std::vector<char>(MAP_WIDTH, '.'));
    
    // Add some obstacles to the map
    addObstacles(baseMap, 10);
    
    // Declare game objects
    Entity player = {5, 9, 100, 'P'}; // Player starts at bottom center
    std::vector<Entity> enemies;
    std::vector<Pickup> pickups; // For medkits etc.
    Weapon weapon = {"Rifle", 6, 6, 6}; // Range, ammo, clip size
    // For D-Day campaign, bunkers with health
    std::vector<Entity> bunkers;
    
    // Campaign-specific configuration
    if (campaign == 1) { // D-Day
        std::cout << "Mission Briefing: D-Day - Your objective is to capture enemy bunkers along the coast.\n";
        // Create bunkers with health 50 at positions (3,0) and (7,0)
        bunkers.push_back({3, 0, 50, 'B'});
        bunkers.push_back({7, 0, 50, 'B'});
        // Mark bunkers on the map
        baseMap[0][3] = 'B';
        baseMap[0][7] = 'B';
        enemies = {
            {3, 3, 50, 'E'},
            {7, 3, 50, 'E'},
            {5, 5, 50, 'E'}
        };
        // Place a medkit pickup
        pickups.push_back({2, 6, 'M', 20});
    } else if (campaign == 2) { // Aden Offensive
        std::cout << "Mission Briefing: Aden Offensive - Hold off enemy forces at all costs!\n";
        enemies = {
            {2, 2, 50, 'E'},
            {4, 3, 50, 'E'},
            {6, 2, 50, 'E'},
            {3, 4, 50, 'E'},
            {7, 4, 50, 'E'} // More enemies
        };
        pickups.push_back({1, 8, 'M', 20});
    } else { // Berlin Attack
        std::cout << "Mission Briefing: Berlin Attack - Capture the flag deep in enemy territory!\n";
        // Use objectives for Berlin Attack (flag)
        baseMap[0][5] = 'F';
        enemies = {
            {4, 2, 50, 'E'},
            {6, 2, 50, 'E'},
            {5, 4, 50, 'E'},
            {3, 3, 50, 'E'}
        };
        pickups.push_back({8, 7, 'M', 20});
    }
    
    // Main game loop for map-based gameplay.
    while (true) {
        render(baseMap, player, enemies, pickups, bunkers, weapon);
        
        // Player input
        char input = _getch();
        int dx = 0, dy = 0;
        bool isMove = false, isShoot = false, isGrenade = false, isReload = false;
        
        // Movement keys (including diagonals)
        if (input == 'w') { dy = -1; isMove = true; }
        else if (input == 's') { dy = 1; isMove = true; }
        else if (input == 'a') { dx = -1; isMove = true; }
        else if (input == 'd') { dx = 1; isMove = true; }
        else if (input == 'q') { dx = -1; dy = -1; isMove = true; }
        else if (input == 'e') { dx = 1; dy = -1; isMove = true; }
        else if (input == 'z') { dx = -1; dy = 1; isMove = true; }
        else if (input == 'c') { dx = 1; dy = 1; isMove = true; }
        // Shooting keys (non-diagonal)
        else if (input == 'i') { dy = -1; isShoot = true; }
        else if (input == 'k') { dy = 1; isShoot = true; }
        else if (input == 'j') { dx = -1; isShoot = true; }
        else if (input == 'l') { dx = 1; isShoot = true; }
        else if (input == 'g') { isGrenade = true; }  // Grenade attack
        else if (input == 'r') { isReload = true; }     // Reload weapon
        
        // Process movement
        if (isMove) {
            int newX = player.x + dx;
            int newY = player.y + dy;
            // Check boundaries and ensure destination is passable ('.' or objectives: bunkers 'B' or flag 'F')
            if (newX >= 0 && newX < MAP_WIDTH && newY >= 0 && newY < MAP_HEIGHT &&
                (baseMap[newY][newX] == '.' || baseMap[newY][newX] == 'B' || baseMap[newY][newX] == 'F')) {
                player.x = newX;
                player.y = newY;
                
                // If D-Day campaign and the destination is a bunker, launch bunker battle.
                if (campaign == 1 && baseMap[newY][newX] == 'B') {
                    // Find the bunker in our vector.
                    auto it = std::find_if(bunkers.begin(), bunkers.end(), [newX, newY](const Entity &b) {
                        return b.x == newX && b.y == newY;
                    });
                    if (it != bunkers.end()) {
                        bool survived = battleBunker(*it, player.health);
                        if (survived) {
                            score += 100;
                            // Remove bunker from map and vector
                            baseMap[newY][newX] = '.';
                            bunkers.erase(it);
                        } else {
                            render(baseMap, player, enemies, pickups, bunkers, weapon);
                            std::cout << "Game Over! You were killed by bunker defenses.\n";
                            return;
                        }
                    }
                }
                // For non-D-Day campaigns, check if an objective (flag) was reached.
                if (campaign == 3 && baseMap[newY][newX] == 'F') {
                    baseMap[newY][newX] = '.';
                    score += 100;
                    std::cout << "Flag captured! (+100 points)\n";
                }
            }
            // Check for pickup collisions
            for (auto it = pickups.begin(); it != pickups.end(); ) {
                if (it->x == player.x && it->y == player.y) {
                    player.health += it->value;
                    if (player.health > 100) player.health = 100;
                    std::cout << "Picked up a medkit! Health restored by " << it->value << ".\n";
                    score += 50;
                    it = pickups.erase(it);
                } else {
                    ++it;
                }
            }
        }
        // Process shooting (overworld shooting against enemies)
        else if (isShoot) {
            if (weapon.ammo <= 0) {
                std::cout << "Out of ammo! Reload (press 'r')!\n";
            } else {
                weapon.ammo--;
                std::cout << "BANG!\n";
                int shotX = player.x + dx;
                int shotY = player.y + dy;
                bool hit = false;
                int rangeCounter = 0;
                while (shotX >= 0 && shotX < MAP_WIDTH && shotY >= 0 && shotY < MAP_HEIGHT && !hit && rangeCounter < weapon.range) {
                    // Stop bullet if it hits an obstacle
                    if (baseMap[shotY][shotX] == '#') {
                        break;
                    }
                    // Check if bullet hits an enemy
                    for (auto it = enemies.begin(); it != enemies.end(); ) {
                        if (it->x == shotX && it->y == shotY) {
                            int damage = 10 + rand() % (20 - 10 + 1);
                            it->health -= damage;
                            std::cout << "Hit enemy at (" << shotX << "," << shotY << ") for " << damage << " damage.\n";
                            if (it->health <= 0) {
                                it = enemies.erase(it);
                                score += 100;
                                std::cout << "Enemy eliminated! (+100 points)\n";
                            } else {
                                ++it;
                            }
                            hit = true;
                            break;
                        } else {
                            ++it;
                        }
                    }
                    if (!hit) {
                        shotX += dx;
                        shotY += dy;
                        rangeCounter++;
                    }
                }
            }
        }
        // Process grenade attack: affects a 3x3 area in a chosen direction.
        else if (isGrenade) {
            std::cout << "BOOM! Grenade exploded.\n";
            std::cout << "Enter grenade direction (i/j/k/l): ";
            char gDir = _getch();
            int centerX = player.x, centerY = player.y;
            if (gDir == 'i') { centerY = player.y - 1; }
            else if (gDir == 'k') { centerY = player.y + 1; }
            else if (gDir == 'j') { centerX = player.x - 1; }
            else if (gDir == 'l') { centerX = player.x + 1; }
            for (auto it = enemies.begin(); it != enemies.end(); ) {
                if (abs(it->x - centerX) <= 1 && abs(it->y - centerY) <= 1) {
                    it->health -= 20;
                    std::cout << "Grenade hit enemy at (" << it->x << "," << it->y << ") for 20 damage.\n";
                    if (it->health <= 0) {
                        it = enemies.erase(it);
                        score += 100;
                        std::cout << "Enemy eliminated by grenade! (+100 points)\n";
                        continue;
                    }
                }
                ++it;
            }
        }
        // Process reload (refill ammo)
        else if (isReload) {
            weapon.ammo = weapon.clipSize;
            std::cout << "Reloading...\n";
        }
        
        // Enemy actions
        for (auto& enemy : enemies) {
            // Enemy shooting if aligned with player
            if (enemy.x == player.x || enemy.y == player.y) {
                int shotDx = (enemy.x == player.x) ? 0 : (enemy.x < player.x ? 1 : -1);
                int shotDy = (enemy.y == player.y) ? 0 : (enemy.y < player.y ? 1 : -1);
                int shotX = enemy.x + shotDx;
                int shotY = enemy.y + shotDy;
                while (shotX >= 0 && shotX < MAP_WIDTH && shotY >= 0 && shotY < MAP_HEIGHT) {
                    if (baseMap[shotY][shotX] == '#') break;
                    if (shotX == player.x && shotY == player.y) {
                        int dmg = 10 + rand() % (15 - 10 + 1);
                        player.health -= dmg;
                        std::cout << "An enemy shot you for " << dmg << " damage!\n";
                        break;
                    }
                    shotX += shotDx;
                    shotY += shotDy;
                }
            } else { 
                // Move enemy toward the player (if path is clear)
                int moveDx = (enemy.x < player.x) ? 1 : (enemy.x > player.x ? -1 : 0);
                int moveDy = (enemy.y < player.y) ? 1 : (enemy.y > player.y ? -1 : 0);
                int newX = enemy.x + moveDx;
                int newY = enemy.y + moveDy;
                if (newX >= 0 && newX < MAP_WIDTH && newY >= 0 && newY < MAP_HEIGHT &&
                    baseMap[newY][newX] == '.') {
                    enemy.x = newX;
                    enemy.y = newY;
                }
            }
        }
        
        // Check win/lose conditions for the map phase.
        if (player.health <= 0) {
            render(baseMap, player, enemies, pickups, bunkers, weapon);
            std::cout << "Game Over! You died during the mission.\n";
            return;
        }
        // For D-Day, win if all bunkers are captured.
        if (campaign == 1 && bunkers.empty()) {
            render(baseMap, player, enemies, pickups, bunkers, weapon);
            std::cout << "\nAll bunkers captured. Initiating final battle...\n";
            bool result = battleEncounter("Bunker Final Assault", player.health, 100, 80);
            if (result)
                std::cout << "Victory! Mission accomplished.\n";
            else
                std::cout << "Defeat! Mission failed in final battle.\n";
            return;
        }
        // For Aden Offensive, win if all enemies are eliminated.
        else if (campaign == 2 && enemies.empty()) {
            render(baseMap, player, enemies, pickups, bunkers, weapon);
            std::cout << "\nAll enemies eliminated. Initiating final battle...\n";
            bool result = battleEncounter("Final Defense", player.health, 120, 90);
            if (result)
                std::cout << "Victory! Mission accomplished.\n";
            else
                std::cout << "Defeat! Mission failed in final battle.\n";
            return;
        }
        // For Berlin Attack, win if the flag has been captured.
        else if (campaign == 3 && baseMap[0][5] != 'F') {
            render(baseMap, player, enemies, pickups, bunkers, weapon);
            std::cout << "\nFlag captured. Initiating final battle...\n";
            bool result = battleEncounter("Flag Defense", player.health, 100, 80);
            if (result)
                std::cout << "Victory! Mission accomplished.\n";
            else
                std::cout << "Defeat! Mission failed in final battle.\n";
            return;
        }
    }
}

int main() {
    srand(static_cast<unsigned int>(time(0)));
    std::cout << "Battleground 1 - Enhanced Edition\n";
    std::cout << "Controls:\n";
    std::cout << "  Movement: w/a/s/d and diagonals (q, e, z, c)\n";
    std::cout << "  Shooting: i/j/k/l for up/left/down/right\n";
    std::cout << "  Grenade: g\n";
    std::cout << "  Reload: r\n";
    std::cout << "\nSelect Campaign:\n1. D-Day\n2. Aden Offensive\n3. Berlin Attack\nEnter choice (1-3): ";
    int choice;
    std::cin >> choice;
    if (choice >= 1 && choice <= 3) {
        playCampaign(choice);
    } else {
        std::cout << "Invalid choice." << std::endl;
    }
    std::cout << "\nPress any key to exit.";
    _getch();
    return 0;
}