package org.project;

import org.project.entity.enemies.*;
import org.project.entity.players.Knight;
import org.project.entity.players.Player;
import org.project.item.*;
import org.project.item.armors.*;
import org.project.item.consumables.Flask;
import org.project.item.weapons.Sword;
import org.project.location.Location;
import org.project.entity.players.Wizard;
import org.project.entity.players.Assassin;
import org.project.ConsoleColors;

import java.util.*;

public class Main {
    private static Scanner input = new Scanner(System.in);
    private static Random rand = new Random();
    private static Player hero;
    private static List<Location> map;
    private static Location castle;
    private static Map<String, Boolean> collectedKeys;

    public static void main(String[] args) {
        setup();
        runGame();
    }
    private static void setup() {
        System.out.print("Choose class (1=Knight, 2=Wizard, 3=Assassin): ");
        int classPick = input.nextInt();
        input.nextLine();

        if (classPick == 1) {
            hero = new Knight("Arin");
        }
        else if (classPick == 2) {
            hero = new Wizard("Merlin");
        }
        else if (classPick == 3) {
            hero = new Assassin("Ezio");
        }
        else {
            hero = new Knight("Arin");
        }
        collectedKeys = new HashMap<>();
        collectedKeys.put("Goblin", false);
        collectedKeys.put("Skeleton", false);
        collectedKeys.put("Vampire", false);

        map = new ArrayList<>();

        Location woods = new Location("Dark Woods");
        woods.addEnemy(new Goblin());
        woods.addEnemy(new Skeleton());
        woods.addEnemy(new Vampire());
        map.add(woods);

        Location crypt = new Location("Ancient Crypt");
        crypt.addEnemy(new Skeleton());
        crypt.addEnemy(new Vampire());
        map.add(crypt);

        castle = new Location("Dragon's Castle");
        castle.addEnemy(new Dragon());
    }
    private static void runGame() {
        while (hero.isAlive()) {
            boolean allKeys = collectedKeys.get("Goblin") && collectedKeys.get("Skeleton") && collectedKeys.get("Vampire");

            if (allKeys) {
                System.out.println("\nYou have all three keys! The castle door creaks open...");
                System.out.println("1. Enter Castle");
                System.out.println("2. Keep exploring");
                int cmd = input.nextInt();
                input.nextLine();
                if (cmd == 1) {
                    fightDragon();
                    return;
                }
            }
            System.out.println("\n--- What do you want to do? ---");
            System.out.println("1. Hunt for enemies");
            System.out.println("2. Travel to another place");
            System.out.println("3. Visit Merchant");
            System.out.println("4. Use a Flask from bag");
            System.out.println("5. Quit game");
            int cmd = input.nextInt();
            input.nextLine();

            if (cmd == 1) {
                randomBattle();
            }
            else if (cmd == 2) {
                travel();
            }
            else if (cmd == 3) {
                merchant();
            }
            else if (cmd == 4) {
                useFlaskOutsideCombat();
            }
            else if (cmd == 5) {
                System.out.println("Farewell, " + hero.getClass().getSimpleName() + ".");
                return;
            }
            else {
                System.out.println("Wrong input.");
            }
        }
        System.out.println(ConsoleColors.RED + "You have fallen... Game Over." + ConsoleColors.RESET);
    }
    private static Enemy getRandomEnemy() {
        int r = rand.nextInt(3);
        if (r == 0) return new Goblin();
        else if (r == 1) return new Skeleton();
        else return new Vampire();
    }
    private static void randomBattle() {
        Location current = map.get(rand.nextInt(map.size()));
        Enemy foe = getRandomEnemy();

        System.out.println("\nA " + foe.getClass().getSimpleName() + " ambushes you in " + current.getName() + "!");
        fight(foe);

        if (hero.isAlive() && !foe.isAlive()) {
            rewards(foe);
        }
    }
    private static String getSpecialAbilityName() {
        if (hero instanceof Knight) return "Shield Bash";
        else if (hero instanceof Wizard) return "Arcane Blast";
        else if (hero instanceof Assassin) return "Shadow Cloak";
        return "Special Ability";
    }
    private static void fight(Enemy foe) {
        while (hero.isAlive() && foe.isAlive()) {
            System.out.println("\n[" + hero.getName() + " | HP: " + hero.getHp() + "/" + hero.getMaxHP() + " | Mana: " + hero.getMp() + "/" + hero.getMaxMP() + "]");
            System.out.println("[" + foe.getClass().getSimpleName() + " | HP: " + foe.getHp() + "/" + foe.getMaxHP() + "]");

            System.out.println("\nChoose action:");
            System.out.println("1. Light Attack (free)");
            System.out.println("2. Heavy Attack (10 Mana)");
            System.out.println("3. Guard (5 Mana)");
            System.out.println("4. Heal yourself (15 Mana)");
            System.out.println("5. " + getSpecialAbilityName() + " (20 Mana)");
            System.out.println("6. Drink a Flask from bag");
            int act = input.nextInt();
            input.nextLine();

            if (act == 1) {
                hero.lightAttack(foe);
            }
            else if (act == 2) {
                hero.heavyAttack(foe);
            }
            else if (act == 3) {
                hero.defend();
            }
            else if (act == 4) {
                if (hero.consumeMana(15)) {
                    hero.heal(20);
                    System.out.println(ConsoleColors.GREEN + "You recover some health." + ConsoleColors.RESET);
                }
                else {
                    System.out.println(ConsoleColors.YELLOW + "Not enough mana to heal!" + ConsoleColors.RESET);
                }
            }
            else if (act == 5) {
                hero.specialAbility(foe);
            }
            else if (act == 6) {
                consumeFlaskInCombat();
            }
            else {
                System.out.println("You hesitate and do nothing.");
            }

            if (!foe.isAlive()) {
                System.out.println("Enemy defeated!");
                break;
            }

            if (foe instanceof Enemy && ((Enemy) foe).isStunned()) {
                System.out.println(foe.getClass().getSimpleName() + " is stunned and skips its turn!");
                ((Enemy) foe).setStunned(false);
            } else {
                System.out.println("\nEnemy attacks!");
                foe.attack(hero);
            }
            if (!hero.isAlive()) {
                System.out.println("You collapse...");
            }
        }
    }

    private static void rewards(Enemy foe) {
        String type = foe.getClass().getSimpleName();
        int xpEarned = 20 + rand.nextInt(30);
        int goldEarned = 5 + rand.nextInt(15);

        hero.addXp(xpEarned);
        hero.addCoins(goldEarned);
        System.out.println("You gain " + xpEarned + " XP and " + goldEarned + " gold coins.");

        if (collectedKeys.containsKey(type) && !collectedKeys.get(type)) {
            double luck = rand.nextDouble();
            if (luck < 0.2) {
                collectedKeys.put(type, true);
                System.out.println(ConsoleColors.PURPLE + "The " + type + " dropped a mysterious key!" + ConsoleColors.RESET);
            }
        }

        hero.heal(hero.getMaxHP());
        hero.fillMana(hero.getMaxMP());
        System.out.println(ConsoleColors.GREEN + "You catch your breath and are fully restored." + ConsoleColors.RESET);
    }
    private static void travel() {
        Location current = map.get(rand.nextInt(map.size()));
        Enemy foe = getRandomEnemy();
        System.out.println("You travel to " + current.getName() + "...");
        System.out.println("A " + foe.getClass().getSimpleName() + " appears!");
        fight(foe);
        if (hero.isAlive() && !foe.isAlive()) {
            rewards(foe);
        }
    }
    private static void fightDragon() {
        System.out.println("You march into the Dragon's lair!");
        Enemy dragon = castle.getEnemies().get(0);
        fight(dragon);
        if (!dragon.isAlive() && hero.isAlive()) {
            System.out.println(ConsoleColors.YELLOW + "The dragon is slain! Javanest is free!" + ConsoleColors.RESET);
        }
    }
    private static void merchant() {
        System.out.println("\n--- Merchant's Stall ---");
        System.out.println("Your gold: " + hero.getCoins());
        System.out.println("1. Buy Iron Sword (30 gold)");
        System.out.println("2. Buy Knight's Armor (50 gold)");
        System.out.println("3. Buy Healing Flask (20 gold)");
        System.out.println("4. Leave");
        int pick = input.nextInt();
        input.nextLine();

        if (pick == 1) {
            if (hero.getCoins() >= 30) {
                hero.addItem(new Sword());
                hero.addCoins(-30);
                System.out.println("You bought an Iron Sword.");
            }
            else {
                System.out.println("Not enough gold.");
            }
        }
        else if (pick == 2) {
            if (hero.getCoins() >= 50) {
                hero.addItem(new KnightArmor());
                hero.addCoins(-50);
                System.out.println("You bought Knight's Armor.");
            }
            else {
                System.out.println("Not enough gold.");
            }
        }
        else if (pick == 3) {
            if (hero.getCoins() >= 20) {
                hero.addItem(new Flask());
                hero.addCoins(-20);
                System.out.println("You bought a Flask.");
            }
            else {
                System.out.println("Not enough gold.");
            }
        }
        else {
            System.out.println("Come back anytime.");
        }
    }
    private static void useFlaskOutsideCombat() {
        for (Item it : hero.getInventory()) {
            if (it instanceof Flask) {
                it.use(hero);
                hero.removeItem(it);
                System.out.println("You drink the flask and feel better.");
                return;
            }
        }
        System.out.println("Your bag has no Flasks.");
    }
    private static void consumeFlaskInCombat() {
        for (Item it : hero.getInventory()) {
            if (it instanceof Flask) {
                it.use(hero);
                hero.removeItem(it);
                System.out.println("You gulp a flask in the heat of battle!");
                return;
            }
        }
        System.out.println("No flask to use.");
    }
}